From 7d45346bb648be6c415467d09947b907271e3aa3 Mon Sep 17 00:00:00 2001 From: Jonathan Bernard Date: Sat, 3 Sep 2022 21:01:24 -0500 Subject: [PATCH] Add generated documentations (for use with GitHub pages). --- .gitignore | 1 - Makefile | 11 +- README.rst | 201 +++- docs/README.html | 202 ++++ docs/dochack.js | 2041 ++++++++++++++++++++++++++++++++++++++ docs/fiber_orm.html | 619 ++++++++++++ docs/fiber_orm.idx | 25 + docs/fiber_orm/pool.html | 303 ++++++ docs/fiber_orm/pool.idx | 6 + docs/fiber_orm/util.html | 524 ++++++++++ docs/fiber_orm/util.idx | 21 + docs/index.html | 619 ++++++++++++ docs/nimdoc.out.css | 1016 +++++++++++++++++++ docs/theindex.html | 246 +++++ src/fiber_orm.nim | 97 +- 15 files changed, 5909 insertions(+), 23 deletions(-) create mode 100644 docs/README.html create mode 100644 docs/dochack.js create mode 100644 docs/fiber_orm.html create mode 100644 docs/fiber_orm.idx create mode 100644 docs/fiber_orm/pool.html create mode 100644 docs/fiber_orm/pool.idx create mode 100644 docs/fiber_orm/util.html create mode 100644 docs/fiber_orm/util.idx create mode 100644 docs/index.html create mode 100644 docs/nimdoc.out.css create mode 100644 docs/theindex.html diff --git a/.gitignore b/.gitignore index 108e8d2..a14a89e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ *.sw? nimcache/ -htmdocs/ diff --git a/Makefile b/Makefile index 88502d7..f2837ef 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,10 @@ SOURCES=$(shell find src -type f) -doc: $(shell find src -type f) - nim doc --project --index:on --git.url:https://github.com/jdbernard/fiber-orm --outdir:htmdocs src/fiber_orm - nim rst2html --outdir:htmdocs README.rst +build: $(shell find src -type f) + nimble build -.PHONY: doc +docs: $(shell find src -type f) + nim doc --project --index:on --git.url:https://github.com/jdbernard/fiber-orm --outdir:docs src/fiber_orm + nim rst2html --outdir:docs README.rst + cp docs/fiber_orm.html docs/index.html +.PHONY: docs diff --git a/README.rst b/README.rst index 289acb4..458d0ba 100644 --- a/README.rst +++ b/README.rst @@ -5,29 +5,224 @@ Lightweight ORM supporting the `Postgres`_ and `SQLite`_ databases in Nim. It supports a simple, opinionated model mapper to generate SQL queries based on Nim objects. It also includes a simple connection pooling implementation. +Fiber ORM is not intended to be a 100% all-cases-covered ORM that handles +every potential data access pattern one might wish to implement. It is best +thought of as a collection of common SQL generation patterns. It is intended +to cover 90% of the common queries and functions one might write when +implementing an SQL-based access layer. It is expected that there may be a +few more complicated queries that need to be implemented to handle specific +access patterns. + +The simple mapping pattern provided by Fiber ORM also works well on top of +databases that encapsulate data access logic in SQL with, for example, +views. + .. _Postgres: https://nim-lang.org/docs/db_postgres.html .. _SQLite: https://nim-lang.org/docs/db_sqlite.html Basic Usage =========== +Consider a simple TODO list application that keeps track of TODO items as +well as time logged against those items. You might have a schema such as: + +.. code-block:: SQL + create extension if not exists "pgcrypto"; + + create table todo_items columns ( + id uuid not null primary key default gen_random_uuid(), + owner varchar not null, + summary varchar not null, + details varchar default null, + priority integer not null default 0, + related_todo_item_ids uuid[] not null default '{}' + ); + + create table time_entries columns ( + id uuid not null primary key default gen_random_uuid(), + todo_item_id uuid not null references todo_items (id) on delete cascade, + start timestamp with timezone not null default current_timestamp, + stop timestamp with timezone default null, + ); + +Models may be defined as: + +.. code-block:: Nim + # models.nim + import std/options, std/times + import uuids + + type + TodoItem* = object + id*: UUID + owner*: string + summary*: string + details*: Option[string] + priority*: int + relatedTodoItemIds*: seq[UUID] + + TimeEntry* = object + id*: UUID + todoItemId*: Option[UUID] + start*: DateTime + stop*: Option[DateTime] + +Using Fiber ORM we can generate a data access layer with: + +.. code-block:: Nim + # db.nim + import fiber_orm + import ./models.nim + + type TodoDB* = DbConnPool + + proc initDb*(connString: string): TodoDB = + fiber_orm.initPool(connect = + proc(): DbConn = open("", "", "", connString)) + + generateProcsForModels(TodoDB, [TodoItem, TimeEntry]) + + generateLookup(TodoDB, TimeEntry, @["todoItemId"]) + +This will generate the following procedures: + +.. code-block:: Nim + proc getTodoItem*(db: TodoDB, id: UUID): TodoItem; + proc getAllTodoItems*(db: TodoDB): seq[TodoItem]; + proc createTodoItem*(db: TodoDB, rec: TodoItem): TodoItem; + proc updateTodoItem*(db: TodoDB, rec: TodoItem): bool; + proc deleteTodoItem*(db: TodoDB, rec: TodoItem): bool; + proc deleteTodoItem*(db: TodoDB, id: UUID): bool; + + proc findTodoItemsWhere*(db: TodoDB, whereClause: string, + values: varargs[string, dbFormat]): seq[TodoItem]; + + proc getTimeEntry*(db: TodoDB, id: UUID): TimeEntry; + proc getAllTimeEntries*(db: TodoDB): seq[TimeEntry]; + proc createTimeEntry*(db: TodoDB, rec: TimeEntry): TimeEntry; + proc updateTimeEntry*(db: TodoDB, rec: TimeEntry): bool; + proc deleteTimeEntry*(db: TodoDB, rec: TimeEntry): bool; + proc deleteTimeEntry*(db: TodoDB, id: UUID): bool; + + proc findTimeEntriesWhere*(db: TodoDB, whereClause: string, + values: varargs[string, dbFormat]): seq[TimeEntry]; + + proc findTimeEntriesByTodoItemId(db: TodoDB, todoItemId: UUID): seq[TimeEntry]; + Object-Relational Modeling ========================== Model Class ----------- -Table Name -`````````` +Fiber ORM uses simple Nim `object`s and `ref object`s as model classes. +Fiber ORM expects there to be one table for each model class. -Column Names +Name Mapping ```````````` +Fiber ORM uses `snake_case` for database identifiers (column names, table +names, etc.) and `camelCase` for Nim identifiers. We automatically convert +model names to and from table names (`TodoItem` <-> `todo_items`), as well +as column names (`userId` <-> `user_id`). + +Notice that table names are automatically pluralized from model class names. +In the above example, you have: + +=========== ================ +Model Class Table Name +=========== ================ +TodoItem todo_items +TimeEntry time_entries +=========== ================ + +Because Nim is style-insensitive, you can generall refer to model classes +and fields using `snake_case`, `camelCase`, or `PascalCase` in your code and +expect Fiber ORM to be able to map the names to DB identifier names properly +(though FiberORM will always use `camelCase` internally). + +See the `identNameToDb`_, `dbNameToIdent`_, `tableName`_ and `dbFormat`_ +procedures in the `fiber_orm/util`_ module for details. + +.. _identNameToDb: fiber_orm/util.html#identNameToDb,string +.. _dbNameToIdent: fiber_orm/util.html#dbNameToIdent,string +.. _tableName: fiber_orm/util.html#tableName,type +.. _dbFormat: fiber_orm/util.html#dbFormat,DateTime +.. _util: fiber_orm/util.html ID Field ```````` +Fiber ORM expects every model class to have a field named `id`, with a +corresponding `id` column in the model table. This field must be either a +`string`, `integer`, or `UUID`_. + +When creating a new record the `id` field will be omitted if it is empty +(`Option.isNone`_, `UUID.isZero`_, value of `0`, or only whitespace). This +is intended to allow for cases like the example where the database may +generate an ID when a new record is inserted. If a non-zero value is +provided, the create call will include the `id` field in the `INSERT` query. + +.. _Option.isNone: https://nim-lang.org/docs/options.html#isNone,Option[T] +.. _UUID.isZero: https://github.com/pragmagic/uuids/blob/8cb8720b567c6bcb261bd1c0f7491bdb5209ad06/uuids.nim#L72 + Supported Data Types -------------------- +The following Nim data types are supported by Fiber ORM: + +=============== ====================== ================= +Nim Type Postgres Type SQLite Type +=============== ====================== ================= +`string` `varchar`_ +`int` `integer`_ +`float` `double`_ +`bool` `boolean`_ +`DateTime`_ `timestamp`_ +`seq[]` `array`_ +`UUID`_ `uuid (pg)`_ +`Option`_ *allows* `NULL` [#f1]_ +`JsonNode`_ `jsonb`_ +=============== ====================== ================= + +.. [#f1] Note that this implies that all `NULL`-able fields should be typed + as optional using `Option[fieldType]`. Conversely, any fields with + non-optional types should also be constrained to be `NOT NULL` in + the database schema. + +.. _DateTime: https://nim-lang.org/docs/times.html#DateTime +.. _UUID: https://github.com/pragmagic/uuids +.. _Option: https://nim-lang.org/docs/options.html#Option +.. _JsonNode: https://nim-lang.org/docs/json.html#JsonNode + +.. _varchar: https://www.postgresql.org/docs/current/datatype-character.html +.. _integer: https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-INT +.. _double: https://www.postgresql.org/docs/current/datatype-numeric.html#DATATYPE-FLOAT +.. _boolean: https://www.postgresql.org/docs/current/datatype-boolean.html +.. _timestamp: https://www.postgresql.org/docs/current/datatype-datetime.html +.. _array: https://www.postgresql.org/docs/current/arrays.html +.. _uuid (pg): https://www.postgresql.org/docs/current/datatype-uuid.html +.. _jsonb: https://www.postgresql.org/docs/current/datatype-json.html + Database Object =============== + +Many of the Fiber ORM macros expect a database object type to be passed. +In the example above the `fiber_orm.DbConnPool`_ object is used as database +object type (aliased as `TodoDB`). This is the intended usage pattern, but +anything can be passed as the database object type so long as there is a +defined `withConn` template that provides an injected `conn: DbConn` object +to the provided statement body. + +For example, a valid database object implementation that opens a new +connection for every request might look like this: + +.. code-block:: Nim + import std/db_postgres + + type TodoDB* = object + connString: string + + template withConn*(db: TodoDB, stmt: untyped): untyped = + let conn {.inject.} = open("", "", "", db.connString) + try: stmt + finally: close(conn) diff --git a/docs/README.html b/docs/README.html new file mode 100644 index 0000000..e25f0c1 --- /dev/null +++ b/docs/README.html @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + +README + + + + + + + + +
+
+

README

+ +

Fiber ORM

Lightweight ORM supporting the Postgres and SQLite databases in Nim. It supports a simple, opinionated model mapper to generate SQL queries based on Nim objects. It also includes a simple connection pooling implementation.

+

Fiber ORM is not intended to be a 100% all-cases-covered ORM that handles every potential data access pattern one might wish to implement. It is best thought of as a collection of common SQL generation patterns. It is intended to cover 90% of the common queries and functions one might write when implementing an SQL-based access layer. It is expected that there may be a few more complicated queries that need to be implemented to handle specific access patterns.

+

The simple mapping pattern provided by Fiber ORM also works well on top of databases that encapsulate data access logic in SQL with, for example, views.

+ +

Basic Usage

Consider a simple TODO list application that keeps track of TODO items as well as time logged against those items. You might have a schema such as:

+
create extension if not exists "pgcrypto";
+
+create table todo_items columns (
+  id uuid not null primary key default gen_random_uuid(),
+  owner varchar not null,
+  summary varchar not null,
+  details varchar default null,
+  priority integer not null default 0,
+  related_todo_item_ids uuid[] not null default '{}'
+);
+
+create table time_entries columns (
+  id uuid not null primary key default gen_random_uuid(),
+  todo_item_id uuid not null references todo_items (id) on delete cascade,
+  start timestamp with timezone not null default current_timestamp,
+  stop timestamp with timezone default null,
+);

Models may be defined as:

+
# models.nim
+import std/options, std/times
+import uuids
+
+type
+  TodoItem* = object
+    id*: UUID
+    owner*: string
+    summary*: string
+    details*: Option[string]
+    priority*: int
+    relatedTodoItemIds*: seq[UUID]
+  
+  TimeEntry* = object
+    id*: UUID
+    todoItemId*: Option[UUID]
+    start*: DateTime
+    stop*: Option[DateTime]

Using Fiber ORM we can generate a data access layer with:

+
# db.nim
+import fiber_orm
+import ./models.nim
+
+type TodoDB* = DbConnPool
+
+proc initDb*(connString: string): TodoDB =
+  fiber_orm.initPool(connect =
+    proc(): DbConn = open("", "", "", connString))
+
+generateProcsForModels(TodoDB, [TodoItem, TimeEntry])
+
+generateLookup(TodoDB, TimeEntry, @["todoItemId"])

This will generate the following procedures:

+
proc getTodoItem*(db: TodoDB, id: UUID): TodoItem;
+proc getAllTodoItems*(db: TodoDB): seq[TodoItem];
+proc createTodoItem*(db: TodoDB, rec: TodoItem): TodoItem;
+proc updateTodoItem*(db: TodoDB, rec: TodoItem): bool;
+proc deleteTodoItem*(db: TodoDB, rec: TodoItem): bool;
+proc deleteTodoItem*(db: TodoDB, id: UUID): bool;
+
+proc findTodoItemsWhere*(db: TodoDB, whereClause: string,
+  values: varargs[string, dbFormat]): seq[TodoItem];
+
+proc getTimeEntry*(db: TodoDB, id: UUID): TimeEntry;
+proc getAllTimeEntries*(db: TodoDB): seq[TimeEntry];
+proc createTimeEntry*(db: TodoDB, rec: TimeEntry): TimeEntry;
+proc updateTimeEntry*(db: TodoDB, rec: TimeEntry): bool;
+proc deleteTimeEntry*(db: TodoDB, rec: TimeEntry): bool;
+proc deleteTimeEntry*(db: TodoDB, id: UUID): bool;
+
+proc findTimeEntriesWhere*(db: TodoDB, whereClause: string,
+  values: varargs[string, dbFormat]): seq[TimeEntry];
+
+proc findTimeEntriesByTodoItemId(db: TodoDB, todoItemId: UUID): seq[TimeEntry];
+

Object-Relational Modeling

+

Model Class

Fiber ORM uses simple Nim objects and ref objects as model classes. Fiber ORM expects there to be one table for each model class.

+ +

Name Mapping

Fiber ORM uses snake_case for database identifiers (column names, table names, etc.) and camelCase for Nim identifiers. We automatically convert model names to and from table names (TodoItem <-> todo_items), as well as column names (userId <-> user_id).

+

Notice that table names are automatically pluralized from model class names. In the above example, you have:

+ + + +
Model ClassTable Name
TodoItemtodo_items
TimeEntrytime_entries

Because Nim is style-insensitive, you can generall refer to model classes and fields using snake_case, camelCase, or PascalCase in your code and expect Fiber ORM to be able to map the names to DB identifier names properly (though FiberORM will always use camelCase internally).

+

See the identNameToDb, dbNameToIdent, tableName and dbFormat procedures in the fiber module for details.

+ +

ID Field

Fiber ORM expects every model class to have a field named id, with a corresponding id column in the model table. This field must be either a string, integer, or UUID.

+

When creating a new record the id field will be omitted if it is empty (Option.isNone, UUID.isZero, value of 0, or only whitespace). This is intended to allow for cases like the example where the database may generate an ID when a new record is inserted. If a non-zero value is provided, the create call will include the id field in the INSERT query.

+ +

Supported Data Types

The following Nim data types are supported by Fiber ORM:

+ + + + + + + + + + +
Nim TypePostgres TypeSQLite Type
stringvarchar
intinteger
floatdouble
boolboolean
DateTimetimestamp
seq[]array
UUIDuuid (pg)
Optionallows NULL [1]
JsonNodejsonb

+
  Note that this implies that all NULL-able fields should be typed as optional using Option[fieldType]. Conversely, any fields with non-optional types should also be constrained to be NOT NULL in the database schema. +
+
+ +

Database Object

Many of the Fiber ORM macros expect a database object type to be passed. In the example above the fiber object is used as database object type (aliased as TodoDB). This is the intended usage pattern, but anything can be passed as the database object type so long as there is a defined withConn template that provides an injected conn: DbConn object to the provided statement body.

+

For example, a valid database object implementation that opens a new connection for every request might look like this:

+
import std/db_postgres
+
+type TodoDB* = object
+  connString: string
+
+template withConn*(db: TodoDB, stmt: untyped): untyped =
+  let conn {.inject.} = open("", "", "", db.connString)
+  try: stmt
+  finally: close(conn)
+ + +
+ +
+
+
+ + + diff --git a/docs/dochack.js b/docs/dochack.js new file mode 100644 index 0000000..c45dde9 --- /dev/null +++ b/docs/dochack.js @@ -0,0 +1,2041 @@ +/* Generated by the Nim Compiler v1.6.6 */ +var framePtr = null; +var excHandler = 0; +var lastJSError = null; +var NTI637534222 = {size: 0, kind: 18, base: null, node: null, finalizer: null}; +var NTI486539822 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI620757115 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757114 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757113 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757112 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757111 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757110 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757109 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757108 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757107 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757106 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757105 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757104 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757103 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757102 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757101 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757100 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757099 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757098 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757097 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757096 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757095 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757094 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757093 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757092 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620756997 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI620757041 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI620757040 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI620757180 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757177 = {size: 0,kind: 25,base: null,node: null,finalizer: null}; +var NTI620757176 = {size: 0, kind: 18, base: null, node: null, finalizer: null}; +var NTI620757089 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI620757179 = {size: 0, kind: 18, base: null, node: null, finalizer: null}; +var NTI620757090 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI620757029 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI620757028 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI620757141 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI620757031 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI620757030 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI620757140 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI620757139 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI620757039 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI620757038 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI620757138 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI620757137 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI620757033 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI620757032 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI620757136 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI620757143 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI620757035 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI620757034 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI620757142 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI33554456 = {size: 0,kind: 31,base: null,node: null,finalizer: null}; +var NTI620757146 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI620757037 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI620757036 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI33554466 = {size: 0,kind: 1,base: null,node: null,finalizer: null}; +var NTI620757010 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI620757009 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI620757017 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI620757016 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI620757015 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI620757014 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI620757011 = {size: 0, kind: 14, base: null, node: null, finalizer: null}; +var NTI620757135 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI620757134 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI620757133 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI620757013 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI620757012 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI620757436 = {size: 0, kind: 24, base: null, node: null, finalizer: null}; +var NTI33555124 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI33555128 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI33555130 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI33555083 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI33555165 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI33554439 = {size: 0,kind: 28,base: null,node: null,finalizer: null}; +var NTI33554440 = {size: 0,kind: 29,base: null,node: null,finalizer: null}; +var NTI33555164 = {size: 0, kind: 22, base: null, node: null, finalizer: null}; +var NTI33555112 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI33555113 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI33555120 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NTI33555122 = {size: 0, kind: 17, base: null, node: null, finalizer: null}; +var NNI33555122 = {kind: 2, len: 0, offset: 0, typ: null, name: null, sons: []}; +NTI33555122.node = NNI33555122; +var NNI33555120 = {kind: 2, len: 0, offset: 0, typ: null, name: null, sons: []}; +NTI33555120.node = NNI33555120; +var NNI33555113 = {kind: 2, len: 0, offset: 0, typ: null, name: null, sons: []}; +NTI33555113.node = NNI33555113; +NTI33555164.base = NTI33555112; +NTI33555165.base = NTI33555112; +var NNI33555112 = {kind: 2, len: 5, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "parent", len: 0, typ: NTI33555164, name: "parent", sons: null}, +{kind: 1, offset: "name", len: 0, typ: NTI33554440, name: "name", sons: null}, +{kind: 1, offset: "message", len: 0, typ: NTI33554439, name: "msg", sons: null}, +{kind: 1, offset: "trace", len: 0, typ: NTI33554439, name: "trace", sons: null}, +{kind: 1, offset: "up", len: 0, typ: NTI33555165, name: "up", sons: null}]}; +NTI33555112.node = NNI33555112; +var NNI33555083 = {kind: 2, len: 0, offset: 0, typ: null, name: null, sons: []}; +NTI33555083.node = NNI33555083; +NTI33555112.base = NTI33555083; +NTI33555113.base = NTI33555112; +NTI33555120.base = NTI33555113; +NTI33555122.base = NTI33555120; +var NNI33555130 = {kind: 2, len: 0, offset: 0, typ: null, name: null, sons: []}; +NTI33555130.node = NNI33555130; +NTI33555130.base = NTI33555113; +var NNI33555128 = {kind: 2, len: 0, offset: 0, typ: null, name: null, sons: []}; +NTI33555128.node = NNI33555128; +NTI33555128.base = NTI33555113; +var NNI33555124 = {kind: 2, len: 0, offset: 0, typ: null, name: null, sons: []}; +NTI33555124.node = NNI33555124; +NTI33555124.base = NTI33555113; +NTI620757133.base = NTI620757012; +NTI620757134.base = NTI620757012; +NTI620757135.base = NTI620757012; +var NNI620757011 = {kind: 2, offset: 0, typ: null, name: null, len: 12, sons: {"1": {kind: 1, offset: 1, typ: NTI620757011, name: "ElementNode", len: 0, sons: null}, +"2": {kind: 1, offset: 2, typ: NTI620757011, name: "AttributeNode", len: 0, sons: null}, +"3": {kind: 1, offset: 3, typ: NTI620757011, name: "TextNode", len: 0, sons: null}, +"4": {kind: 1, offset: 4, typ: NTI620757011, name: "CDATANode", len: 0, sons: null}, +"5": {kind: 1, offset: 5, typ: NTI620757011, name: "EntityRefNode", len: 0, sons: null}, +"6": {kind: 1, offset: 6, typ: NTI620757011, name: "EntityNode", len: 0, sons: null}, +"7": {kind: 1, offset: 7, typ: NTI620757011, name: "ProcessingInstructionNode", len: 0, sons: null}, +"8": {kind: 1, offset: 8, typ: NTI620757011, name: "CommentNode", len: 0, sons: null}, +"9": {kind: 1, offset: 9, typ: NTI620757011, name: "DocumentNode", len: 0, sons: null}, +"10": {kind: 1, offset: 10, typ: NTI620757011, name: "DocumentTypeNode", len: 0, sons: null}, +"11": {kind: 1, offset: 11, typ: NTI620757011, name: "DocumentFragmentNode", len: 0, sons: null}, +"12": {kind: 1, offset: 12, typ: NTI620757011, name: "NotationNode", len: 0, sons: null}}}; +NTI620757011.node = NNI620757011; +var NNI620757010 = {kind: 2, len: 0, offset: 0, typ: null, name: null, sons: []}; +NTI620757010.node = NNI620757010; +NTI620757010.base = NTI33555083; +NTI620757009.base = NTI620757010; +NTI620757146.base = NTI620757016; +var NNI620757037 = {kind: 2, len: 10, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "acceptCharset", len: 0, typ: NTI33554440, name: "acceptCharset", sons: null}, +{kind: 1, offset: "action", len: 0, typ: NTI33554440, name: "action", sons: null}, +{kind: 1, offset: "autocomplete", len: 0, typ: NTI33554440, name: "autocomplete", sons: null}, +{kind: 1, offset: "elements", len: 0, typ: NTI620757146, name: "elements", sons: null}, +{kind: 1, offset: "encoding", len: 0, typ: NTI33554440, name: "encoding", sons: null}, +{kind: 1, offset: "enctype", len: 0, typ: NTI33554440, name: "enctype", sons: null}, +{kind: 1, offset: "length", len: 0, typ: NTI33554456, name: "length", sons: null}, +{kind: 1, offset: "method", len: 0, typ: NTI33554440, name: "method", sons: null}, +{kind: 1, offset: "noValidate", len: 0, typ: NTI33554466, name: "noValidate", sons: null}, +{kind: 1, offset: "target", len: 0, typ: NTI33554440, name: "target", sons: null}]}; +NTI620757037.node = NNI620757037; +NTI620757037.base = NTI620757017; +NTI620757036.base = NTI620757037; +var NNI620757035 = {kind: 2, len: 5, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "defaultSelected", len: 0, typ: NTI33554466, name: "defaultSelected", sons: null}, +{kind: 1, offset: "selected", len: 0, typ: NTI33554466, name: "selected", sons: null}, +{kind: 1, offset: "selectedIndex", len: 0, typ: NTI33554456, name: "selectedIndex", sons: null}, +{kind: 1, offset: "text", len: 0, typ: NTI33554440, name: "text", sons: null}, +{kind: 1, offset: "value", len: 0, typ: NTI33554440, name: "value", sons: null}]}; +NTI620757035.node = NNI620757035; +NTI620757035.base = NTI620757017; +NTI620757034.base = NTI620757035; +NTI620757142.base = NTI620757034; +NTI620757143.base = NTI620757034; +var NNI620757017 = {kind: 2, len: 20, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "className", len: 0, typ: NTI33554440, name: "className", sons: null}, +{kind: 1, offset: "classList", len: 0, typ: NTI620757009, name: "classList", sons: null}, +{kind: 1, offset: "checked", len: 0, typ: NTI33554466, name: "checked", sons: null}, +{kind: 1, offset: "defaultChecked", len: 0, typ: NTI33554466, name: "defaultChecked", sons: null}, +{kind: 1, offset: "defaultValue", len: 0, typ: NTI33554440, name: "defaultValue", sons: null}, +{kind: 1, offset: "disabled", len: 0, typ: NTI33554466, name: "disabled", sons: null}, +{kind: 1, offset: "form", len: 0, typ: NTI620757036, name: "form", sons: null}, +{kind: 1, offset: "name", len: 0, typ: NTI33554440, name: "name", sons: null}, +{kind: 1, offset: "readOnly", len: 0, typ: NTI33554466, name: "readOnly", sons: null}, +{kind: 1, offset: "options", len: 0, typ: NTI620757142, name: "options", sons: null}, +{kind: 1, offset: "selectedOptions", len: 0, typ: NTI620757143, name: "selectedOptions", sons: null}, +{kind: 1, offset: "clientWidth", len: 0, typ: NTI33554456, name: "clientWidth", sons: null}, +{kind: 1, offset: "clientHeight", len: 0, typ: NTI33554456, name: "clientHeight", sons: null}, +{kind: 1, offset: "contentEditable", len: 0, typ: NTI33554440, name: "contentEditable", sons: null}, +{kind: 1, offset: "isContentEditable", len: 0, typ: NTI33554466, name: "isContentEditable", sons: null}, +{kind: 1, offset: "dir", len: 0, typ: NTI33554440, name: "dir", sons: null}, +{kind: 1, offset: "offsetHeight", len: 0, typ: NTI33554456, name: "offsetHeight", sons: null}, +{kind: 1, offset: "offsetWidth", len: 0, typ: NTI33554456, name: "offsetWidth", sons: null}, +{kind: 1, offset: "offsetLeft", len: 0, typ: NTI33554456, name: "offsetLeft", sons: null}, +{kind: 1, offset: "offsetTop", len: 0, typ: NTI33554456, name: "offsetTop", sons: null}]}; +NTI620757017.node = NNI620757017; +NTI620757017.base = NTI620757013; +NTI620757016.base = NTI620757017; +var NNI620757033 = {kind: 2, len: 3, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "text", len: 0, typ: NTI33554440, name: "text", sons: null}, +{kind: 1, offset: "x", len: 0, typ: NTI33554456, name: "x", sons: null}, +{kind: 1, offset: "y", len: 0, typ: NTI33554456, name: "y", sons: null}]}; +NTI620757033.node = NNI620757033; +NTI620757033.base = NTI620757017; +NTI620757032.base = NTI620757033; +NTI620757136.base = NTI620757032; +NTI620757137.base = NTI620757036; +var NNI620757039 = {kind: 2, len: 8, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "border", len: 0, typ: NTI33554456, name: "border", sons: null}, +{kind: 1, offset: "complete", len: 0, typ: NTI33554466, name: "complete", sons: null}, +{kind: 1, offset: "height", len: 0, typ: NTI33554456, name: "height", sons: null}, +{kind: 1, offset: "hspace", len: 0, typ: NTI33554456, name: "hspace", sons: null}, +{kind: 1, offset: "lowsrc", len: 0, typ: NTI33554440, name: "lowsrc", sons: null}, +{kind: 1, offset: "src", len: 0, typ: NTI33554440, name: "src", sons: null}, +{kind: 1, offset: "vspace", len: 0, typ: NTI33554456, name: "vspace", sons: null}, +{kind: 1, offset: "width", len: 0, typ: NTI33554456, name: "width", sons: null}]}; +NTI620757039.node = NNI620757039; +NTI620757039.base = NTI620757017; +NTI620757038.base = NTI620757039; +NTI620757138.base = NTI620757038; +NTI620757139.base = NTI620757016; +var NNI620757031 = {kind: 2, len: 6, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "height", len: 0, typ: NTI33554456, name: "height", sons: null}, +{kind: 1, offset: "hspace", len: 0, typ: NTI33554456, name: "hspace", sons: null}, +{kind: 1, offset: "src", len: 0, typ: NTI33554440, name: "src", sons: null}, +{kind: 1, offset: "width", len: 0, typ: NTI33554456, name: "width", sons: null}, +{kind: 1, offset: "type", len: 0, typ: NTI33554440, name: "type", sons: null}, +{kind: 1, offset: "vspace", len: 0, typ: NTI33554456, name: "vspace", sons: null}]}; +NTI620757031.node = NNI620757031; +NTI620757031.base = NTI620757017; +NTI620757030.base = NTI620757031; +NTI620757140.base = NTI620757030; +var NNI620757029 = {kind: 2, len: 4, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "target", len: 0, typ: NTI33554440, name: "target", sons: null}, +{kind: 1, offset: "text", len: 0, typ: NTI33554440, name: "text", sons: null}, +{kind: 1, offset: "x", len: 0, typ: NTI33554456, name: "x", sons: null}, +{kind: 1, offset: "y", len: 0, typ: NTI33554456, name: "y", sons: null}]}; +NTI620757029.node = NNI620757029; +NTI620757029.base = NTI620757017; +NTI620757028.base = NTI620757029; +NTI620757141.base = NTI620757028; +var NNI620757176 = {kind: 1, offset: "then", len: 0, typ: NTI620757177, name: "then", sons: null}; +NTI620757176.node = NNI620757176; +NTI620757089.base = NTI620757176; +var NNI620757179 = {kind: 2, len: 2, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "ready", len: 0, typ: NTI620757089, name: "ready", sons: null}, +{kind: 1, offset: "onloadingdone", len: 0, typ: NTI620757180, name: "onloadingdone", sons: null}]}; +NTI620757179.node = NNI620757179; +NTI620757090.base = NTI620757179; +var NNI620757015 = {kind: 2, len: 23, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "activeElement", len: 0, typ: NTI620757016, name: "activeElement", sons: null}, +{kind: 1, offset: "documentElement", len: 0, typ: NTI620757016, name: "documentElement", sons: null}, +{kind: 1, offset: "alinkColor", len: 0, typ: NTI33554440, name: "alinkColor", sons: null}, +{kind: 1, offset: "bgColor", len: 0, typ: NTI33554440, name: "bgColor", sons: null}, +{kind: 1, offset: "body", len: 0, typ: NTI620757016, name: "body", sons: null}, +{kind: 1, offset: "charset", len: 0, typ: NTI33554440, name: "charset", sons: null}, +{kind: 1, offset: "cookie", len: 0, typ: NTI33554440, name: "cookie", sons: null}, +{kind: 1, offset: "defaultCharset", len: 0, typ: NTI33554440, name: "defaultCharset", sons: null}, +{kind: 1, offset: "fgColor", len: 0, typ: NTI33554440, name: "fgColor", sons: null}, +{kind: 1, offset: "head", len: 0, typ: NTI620757016, name: "head", sons: null}, +{kind: 1, offset: "lastModified", len: 0, typ: NTI33554440, name: "lastModified", sons: null}, +{kind: 1, offset: "linkColor", len: 0, typ: NTI33554440, name: "linkColor", sons: null}, +{kind: 1, offset: "referrer", len: 0, typ: NTI33554440, name: "referrer", sons: null}, +{kind: 1, offset: "title", len: 0, typ: NTI33554440, name: "title", sons: null}, +{kind: 1, offset: "URL", len: 0, typ: NTI33554440, name: "URL", sons: null}, +{kind: 1, offset: "vlinkColor", len: 0, typ: NTI33554440, name: "vlinkColor", sons: null}, +{kind: 1, offset: "anchors", len: 0, typ: NTI620757136, name: "anchors", sons: null}, +{kind: 1, offset: "forms", len: 0, typ: NTI620757137, name: "forms", sons: null}, +{kind: 1, offset: "images", len: 0, typ: NTI620757138, name: "images", sons: null}, +{kind: 1, offset: "applets", len: 0, typ: NTI620757139, name: "applets", sons: null}, +{kind: 1, offset: "embeds", len: 0, typ: NTI620757140, name: "embeds", sons: null}, +{kind: 1, offset: "links", len: 0, typ: NTI620757141, name: "links", sons: null}, +{kind: 1, offset: "fonts", len: 0, typ: NTI620757090, name: "fonts", sons: null}]}; +NTI620757015.node = NNI620757015; +NTI620757015.base = NTI620757013; +NTI620757014.base = NTI620757015; +var NNI620757041 = {kind: 2, len: 368, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "alignContent", len: 0, typ: NTI33554440, name: "alignContent", sons: null}, +{kind: 1, offset: "alignItems", len: 0, typ: NTI33554440, name: "alignItems", sons: null}, +{kind: 1, offset: "alignSelf", len: 0, typ: NTI33554440, name: "alignSelf", sons: null}, +{kind: 1, offset: "all", len: 0, typ: NTI33554440, name: "all", sons: null}, +{kind: 1, offset: "animation", len: 0, typ: NTI33554440, name: "animation", sons: null}, +{kind: 1, offset: "animationDelay", len: 0, typ: NTI33554440, name: "animationDelay", sons: null}, +{kind: 1, offset: "animationDirection", len: 0, typ: NTI33554440, name: "animationDirection", sons: null}, +{kind: 1, offset: "animationDuration", len: 0, typ: NTI33554440, name: "animationDuration", sons: null}, +{kind: 1, offset: "animationFillMode", len: 0, typ: NTI33554440, name: "animationFillMode", sons: null}, +{kind: 1, offset: "animationIterationCount", len: 0, typ: NTI33554440, name: "animationIterationCount", sons: null}, +{kind: 1, offset: "animationName", len: 0, typ: NTI33554440, name: "animationName", sons: null}, +{kind: 1, offset: "animationPlayState", len: 0, typ: NTI33554440, name: "animationPlayState", sons: null}, +{kind: 1, offset: "animationTimingFunction", len: 0, typ: NTI33554440, name: "animationTimingFunction", sons: null}, +{kind: 1, offset: "backdropFilter", len: 0, typ: NTI33554440, name: "backdropFilter", sons: null}, +{kind: 1, offset: "backfaceVisibility", len: 0, typ: NTI33554440, name: "backfaceVisibility", sons: null}, +{kind: 1, offset: "background", len: 0, typ: NTI33554440, name: "background", sons: null}, +{kind: 1, offset: "backgroundAttachment", len: 0, typ: NTI33554440, name: "backgroundAttachment", sons: null}, +{kind: 1, offset: "backgroundBlendMode", len: 0, typ: NTI33554440, name: "backgroundBlendMode", sons: null}, +{kind: 1, offset: "backgroundClip", len: 0, typ: NTI33554440, name: "backgroundClip", sons: null}, +{kind: 1, offset: "backgroundColor", len: 0, typ: NTI33554440, name: "backgroundColor", sons: null}, +{kind: 1, offset: "backgroundImage", len: 0, typ: NTI33554440, name: "backgroundImage", sons: null}, +{kind: 1, offset: "backgroundOrigin", len: 0, typ: NTI33554440, name: "backgroundOrigin", sons: null}, +{kind: 1, offset: "backgroundPosition", len: 0, typ: NTI33554440, name: "backgroundPosition", sons: null}, +{kind: 1, offset: "backgroundRepeat", len: 0, typ: NTI33554440, name: "backgroundRepeat", sons: null}, +{kind: 1, offset: "backgroundSize", len: 0, typ: NTI33554440, name: "backgroundSize", sons: null}, +{kind: 1, offset: "blockSize", len: 0, typ: NTI33554440, name: "blockSize", sons: null}, +{kind: 1, offset: "border", len: 0, typ: NTI33554440, name: "border", sons: null}, +{kind: 1, offset: "borderBlock", len: 0, typ: NTI33554440, name: "borderBlock", sons: null}, +{kind: 1, offset: "borderBlockColor", len: 0, typ: NTI33554440, name: "borderBlockColor", sons: null}, +{kind: 1, offset: "borderBlockEnd", len: 0, typ: NTI33554440, name: "borderBlockEnd", sons: null}, +{kind: 1, offset: "borderBlockEndColor", len: 0, typ: NTI33554440, name: "borderBlockEndColor", sons: null}, +{kind: 1, offset: "borderBlockEndStyle", len: 0, typ: NTI33554440, name: "borderBlockEndStyle", sons: null}, +{kind: 1, offset: "borderBlockEndWidth", len: 0, typ: NTI33554440, name: "borderBlockEndWidth", sons: null}, +{kind: 1, offset: "borderBlockStart", len: 0, typ: NTI33554440, name: "borderBlockStart", sons: null}, +{kind: 1, offset: "borderBlockStartColor", len: 0, typ: NTI33554440, name: "borderBlockStartColor", sons: null}, +{kind: 1, offset: "borderBlockStartStyle", len: 0, typ: NTI33554440, name: "borderBlockStartStyle", sons: null}, +{kind: 1, offset: "borderBlockStartWidth", len: 0, typ: NTI33554440, name: "borderBlockStartWidth", sons: null}, +{kind: 1, offset: "borderBlockStyle", len: 0, typ: NTI33554440, name: "borderBlockStyle", sons: null}, +{kind: 1, offset: "borderBlockWidth", len: 0, typ: NTI33554440, name: "borderBlockWidth", sons: null}, +{kind: 1, offset: "borderBottom", len: 0, typ: NTI33554440, name: "borderBottom", sons: null}, +{kind: 1, offset: "borderBottomColor", len: 0, typ: NTI33554440, name: "borderBottomColor", sons: null}, +{kind: 1, offset: "borderBottomLeftRadius", len: 0, typ: NTI33554440, name: "borderBottomLeftRadius", sons: null}, +{kind: 1, offset: "borderBottomRightRadius", len: 0, typ: NTI33554440, name: "borderBottomRightRadius", sons: null}, +{kind: 1, offset: "borderBottomStyle", len: 0, typ: NTI33554440, name: "borderBottomStyle", sons: null}, +{kind: 1, offset: "borderBottomWidth", len: 0, typ: NTI33554440, name: "borderBottomWidth", sons: null}, +{kind: 1, offset: "borderCollapse", len: 0, typ: NTI33554440, name: "borderCollapse", sons: null}, +{kind: 1, offset: "borderColor", len: 0, typ: NTI33554440, name: "borderColor", sons: null}, +{kind: 1, offset: "borderEndEndRadius", len: 0, typ: NTI33554440, name: "borderEndEndRadius", sons: null}, +{kind: 1, offset: "borderEndStartRadius", len: 0, typ: NTI33554440, name: "borderEndStartRadius", sons: null}, +{kind: 1, offset: "borderImage", len: 0, typ: NTI33554440, name: "borderImage", sons: null}, +{kind: 1, offset: "borderImageOutset", len: 0, typ: NTI33554440, name: "borderImageOutset", sons: null}, +{kind: 1, offset: "borderImageRepeat", len: 0, typ: NTI33554440, name: "borderImageRepeat", sons: null}, +{kind: 1, offset: "borderImageSlice", len: 0, typ: NTI33554440, name: "borderImageSlice", sons: null}, +{kind: 1, offset: "borderImageSource", len: 0, typ: NTI33554440, name: "borderImageSource", sons: null}, +{kind: 1, offset: "borderImageWidth", len: 0, typ: NTI33554440, name: "borderImageWidth", sons: null}, +{kind: 1, offset: "borderInline", len: 0, typ: NTI33554440, name: "borderInline", sons: null}, +{kind: 1, offset: "borderInlineColor", len: 0, typ: NTI33554440, name: "borderInlineColor", sons: null}, +{kind: 1, offset: "borderInlineEnd", len: 0, typ: NTI33554440, name: "borderInlineEnd", sons: null}, +{kind: 1, offset: "borderInlineEndColor", len: 0, typ: NTI33554440, name: "borderInlineEndColor", sons: null}, +{kind: 1, offset: "borderInlineEndStyle", len: 0, typ: NTI33554440, name: "borderInlineEndStyle", sons: null}, +{kind: 1, offset: "borderInlineEndWidth", len: 0, typ: NTI33554440, name: "borderInlineEndWidth", sons: null}, +{kind: 1, offset: "borderInlineStart", len: 0, typ: NTI33554440, name: "borderInlineStart", sons: null}, +{kind: 1, offset: "borderInlineStartColor", len: 0, typ: NTI33554440, name: "borderInlineStartColor", sons: null}, +{kind: 1, offset: "borderInlineStartStyle", len: 0, typ: NTI33554440, name: "borderInlineStartStyle", sons: null}, +{kind: 1, offset: "borderInlineStartWidth", len: 0, typ: NTI33554440, name: "borderInlineStartWidth", sons: null}, +{kind: 1, offset: "borderInlineStyle", len: 0, typ: NTI33554440, name: "borderInlineStyle", sons: null}, +{kind: 1, offset: "borderInlineWidth", len: 0, typ: NTI33554440, name: "borderInlineWidth", sons: null}, +{kind: 1, offset: "borderLeft", len: 0, typ: NTI33554440, name: "borderLeft", sons: null}, +{kind: 1, offset: "borderLeftColor", len: 0, typ: NTI33554440, name: "borderLeftColor", sons: null}, +{kind: 1, offset: "borderLeftStyle", len: 0, typ: NTI33554440, name: "borderLeftStyle", sons: null}, +{kind: 1, offset: "borderLeftWidth", len: 0, typ: NTI33554440, name: "borderLeftWidth", sons: null}, +{kind: 1, offset: "borderRadius", len: 0, typ: NTI33554440, name: "borderRadius", sons: null}, +{kind: 1, offset: "borderRight", len: 0, typ: NTI33554440, name: "borderRight", sons: null}, +{kind: 1, offset: "borderRightColor", len: 0, typ: NTI33554440, name: "borderRightColor", sons: null}, +{kind: 1, offset: "borderRightStyle", len: 0, typ: NTI33554440, name: "borderRightStyle", sons: null}, +{kind: 1, offset: "borderRightWidth", len: 0, typ: NTI33554440, name: "borderRightWidth", sons: null}, +{kind: 1, offset: "borderSpacing", len: 0, typ: NTI33554440, name: "borderSpacing", sons: null}, +{kind: 1, offset: "borderStartEndRadius", len: 0, typ: NTI33554440, name: "borderStartEndRadius", sons: null}, +{kind: 1, offset: "borderStartStartRadius", len: 0, typ: NTI33554440, name: "borderStartStartRadius", sons: null}, +{kind: 1, offset: "borderStyle", len: 0, typ: NTI33554440, name: "borderStyle", sons: null}, +{kind: 1, offset: "borderTop", len: 0, typ: NTI33554440, name: "borderTop", sons: null}, +{kind: 1, offset: "borderTopColor", len: 0, typ: NTI33554440, name: "borderTopColor", sons: null}, +{kind: 1, offset: "borderTopLeftRadius", len: 0, typ: NTI33554440, name: "borderTopLeftRadius", sons: null}, +{kind: 1, offset: "borderTopRightRadius", len: 0, typ: NTI33554440, name: "borderTopRightRadius", sons: null}, +{kind: 1, offset: "borderTopStyle", len: 0, typ: NTI33554440, name: "borderTopStyle", sons: null}, +{kind: 1, offset: "borderTopWidth", len: 0, typ: NTI33554440, name: "borderTopWidth", sons: null}, +{kind: 1, offset: "borderWidth", len: 0, typ: NTI33554440, name: "borderWidth", sons: null}, +{kind: 1, offset: "bottom", len: 0, typ: NTI33554440, name: "bottom", sons: null}, +{kind: 1, offset: "boxDecorationBreak", len: 0, typ: NTI33554440, name: "boxDecorationBreak", sons: null}, +{kind: 1, offset: "boxShadow", len: 0, typ: NTI33554440, name: "boxShadow", sons: null}, +{kind: 1, offset: "boxSizing", len: 0, typ: NTI33554440, name: "boxSizing", sons: null}, +{kind: 1, offset: "breakAfter", len: 0, typ: NTI33554440, name: "breakAfter", sons: null}, +{kind: 1, offset: "breakBefore", len: 0, typ: NTI33554440, name: "breakBefore", sons: null}, +{kind: 1, offset: "breakInside", len: 0, typ: NTI33554440, name: "breakInside", sons: null}, +{kind: 1, offset: "captionSide", len: 0, typ: NTI33554440, name: "captionSide", sons: null}, +{kind: 1, offset: "caretColor", len: 0, typ: NTI33554440, name: "caretColor", sons: null}, +{kind: 1, offset: "clear", len: 0, typ: NTI33554440, name: "clear", sons: null}, +{kind: 1, offset: "clip", len: 0, typ: NTI33554440, name: "clip", sons: null}, +{kind: 1, offset: "clipPath", len: 0, typ: NTI33554440, name: "clipPath", sons: null}, +{kind: 1, offset: "color", len: 0, typ: NTI33554440, name: "color", sons: null}, +{kind: 1, offset: "colorAdjust", len: 0, typ: NTI33554440, name: "colorAdjust", sons: null}, +{kind: 1, offset: "columnCount", len: 0, typ: NTI33554440, name: "columnCount", sons: null}, +{kind: 1, offset: "columnFill", len: 0, typ: NTI33554440, name: "columnFill", sons: null}, +{kind: 1, offset: "columnGap", len: 0, typ: NTI33554440, name: "columnGap", sons: null}, +{kind: 1, offset: "columnRule", len: 0, typ: NTI33554440, name: "columnRule", sons: null}, +{kind: 1, offset: "columnRuleColor", len: 0, typ: NTI33554440, name: "columnRuleColor", sons: null}, +{kind: 1, offset: "columnRuleStyle", len: 0, typ: NTI33554440, name: "columnRuleStyle", sons: null}, +{kind: 1, offset: "columnRuleWidth", len: 0, typ: NTI33554440, name: "columnRuleWidth", sons: null}, +{kind: 1, offset: "columnSpan", len: 0, typ: NTI33554440, name: "columnSpan", sons: null}, +{kind: 1, offset: "columnWidth", len: 0, typ: NTI33554440, name: "columnWidth", sons: null}, +{kind: 1, offset: "columns", len: 0, typ: NTI33554440, name: "columns", sons: null}, +{kind: 1, offset: "contain", len: 0, typ: NTI33554440, name: "contain", sons: null}, +{kind: 1, offset: "content", len: 0, typ: NTI33554440, name: "content", sons: null}, +{kind: 1, offset: "counterIncrement", len: 0, typ: NTI33554440, name: "counterIncrement", sons: null}, +{kind: 1, offset: "counterReset", len: 0, typ: NTI33554440, name: "counterReset", sons: null}, +{kind: 1, offset: "counterSet", len: 0, typ: NTI33554440, name: "counterSet", sons: null}, +{kind: 1, offset: "cursor", len: 0, typ: NTI33554440, name: "cursor", sons: null}, +{kind: 1, offset: "direction", len: 0, typ: NTI33554440, name: "direction", sons: null}, +{kind: 1, offset: "display", len: 0, typ: NTI33554440, name: "display", sons: null}, +{kind: 1, offset: "emptyCells", len: 0, typ: NTI33554440, name: "emptyCells", sons: null}, +{kind: 1, offset: "filter", len: 0, typ: NTI33554440, name: "filter", sons: null}, +{kind: 1, offset: "flex", len: 0, typ: NTI33554440, name: "flex", sons: null}, +{kind: 1, offset: "flexBasis", len: 0, typ: NTI33554440, name: "flexBasis", sons: null}, +{kind: 1, offset: "flexDirection", len: 0, typ: NTI33554440, name: "flexDirection", sons: null}, +{kind: 1, offset: "flexFlow", len: 0, typ: NTI33554440, name: "flexFlow", sons: null}, +{kind: 1, offset: "flexGrow", len: 0, typ: NTI33554440, name: "flexGrow", sons: null}, +{kind: 1, offset: "flexShrink", len: 0, typ: NTI33554440, name: "flexShrink", sons: null}, +{kind: 1, offset: "flexWrap", len: 0, typ: NTI33554440, name: "flexWrap", sons: null}, +{kind: 1, offset: "cssFloat", len: 0, typ: NTI33554440, name: "cssFloat", sons: null}, +{kind: 1, offset: "font", len: 0, typ: NTI33554440, name: "font", sons: null}, +{kind: 1, offset: "fontFamily", len: 0, typ: NTI33554440, name: "fontFamily", sons: null}, +{kind: 1, offset: "fontFeatureSettings", len: 0, typ: NTI33554440, name: "fontFeatureSettings", sons: null}, +{kind: 1, offset: "fontKerning", len: 0, typ: NTI33554440, name: "fontKerning", sons: null}, +{kind: 1, offset: "fontLanguageOverride", len: 0, typ: NTI33554440, name: "fontLanguageOverride", sons: null}, +{kind: 1, offset: "fontOpticalSizing", len: 0, typ: NTI33554440, name: "fontOpticalSizing", sons: null}, +{kind: 1, offset: "fontSize", len: 0, typ: NTI33554440, name: "fontSize", sons: null}, +{kind: 1, offset: "fontSizeAdjust", len: 0, typ: NTI33554440, name: "fontSizeAdjust", sons: null}, +{kind: 1, offset: "fontStretch", len: 0, typ: NTI33554440, name: "fontStretch", sons: null}, +{kind: 1, offset: "fontStyle", len: 0, typ: NTI33554440, name: "fontStyle", sons: null}, +{kind: 1, offset: "fontSynthesis", len: 0, typ: NTI33554440, name: "fontSynthesis", sons: null}, +{kind: 1, offset: "fontVariant", len: 0, typ: NTI33554440, name: "fontVariant", sons: null}, +{kind: 1, offset: "fontVariantAlternates", len: 0, typ: NTI33554440, name: "fontVariantAlternates", sons: null}, +{kind: 1, offset: "fontVariantCaps", len: 0, typ: NTI33554440, name: "fontVariantCaps", sons: null}, +{kind: 1, offset: "fontVariantEastAsian", len: 0, typ: NTI33554440, name: "fontVariantEastAsian", sons: null}, +{kind: 1, offset: "fontVariantLigatures", len: 0, typ: NTI33554440, name: "fontVariantLigatures", sons: null}, +{kind: 1, offset: "fontVariantNumeric", len: 0, typ: NTI33554440, name: "fontVariantNumeric", sons: null}, +{kind: 1, offset: "fontVariantPosition", len: 0, typ: NTI33554440, name: "fontVariantPosition", sons: null}, +{kind: 1, offset: "fontVariationSettings", len: 0, typ: NTI33554440, name: "fontVariationSettings", sons: null}, +{kind: 1, offset: "fontWeight", len: 0, typ: NTI33554440, name: "fontWeight", sons: null}, +{kind: 1, offset: "gap", len: 0, typ: NTI33554440, name: "gap", sons: null}, +{kind: 1, offset: "grid", len: 0, typ: NTI33554440, name: "grid", sons: null}, +{kind: 1, offset: "gridArea", len: 0, typ: NTI33554440, name: "gridArea", sons: null}, +{kind: 1, offset: "gridAutoColumns", len: 0, typ: NTI33554440, name: "gridAutoColumns", sons: null}, +{kind: 1, offset: "gridAutoFlow", len: 0, typ: NTI33554440, name: "gridAutoFlow", sons: null}, +{kind: 1, offset: "gridAutoRows", len: 0, typ: NTI33554440, name: "gridAutoRows", sons: null}, +{kind: 1, offset: "gridColumn", len: 0, typ: NTI33554440, name: "gridColumn", sons: null}, +{kind: 1, offset: "gridColumnEnd", len: 0, typ: NTI33554440, name: "gridColumnEnd", sons: null}, +{kind: 1, offset: "gridColumnStart", len: 0, typ: NTI33554440, name: "gridColumnStart", sons: null}, +{kind: 1, offset: "gridRow", len: 0, typ: NTI33554440, name: "gridRow", sons: null}, +{kind: 1, offset: "gridRowEnd", len: 0, typ: NTI33554440, name: "gridRowEnd", sons: null}, +{kind: 1, offset: "gridRowStart", len: 0, typ: NTI33554440, name: "gridRowStart", sons: null}, +{kind: 1, offset: "gridTemplate", len: 0, typ: NTI33554440, name: "gridTemplate", sons: null}, +{kind: 1, offset: "gridTemplateAreas", len: 0, typ: NTI33554440, name: "gridTemplateAreas", sons: null}, +{kind: 1, offset: "gridTemplateColumns", len: 0, typ: NTI33554440, name: "gridTemplateColumns", sons: null}, +{kind: 1, offset: "gridTemplateRows", len: 0, typ: NTI33554440, name: "gridTemplateRows", sons: null}, +{kind: 1, offset: "hangingPunctuation", len: 0, typ: NTI33554440, name: "hangingPunctuation", sons: null}, +{kind: 1, offset: "height", len: 0, typ: NTI33554440, name: "height", sons: null}, +{kind: 1, offset: "hyphens", len: 0, typ: NTI33554440, name: "hyphens", sons: null}, +{kind: 1, offset: "imageOrientation", len: 0, typ: NTI33554440, name: "imageOrientation", sons: null}, +{kind: 1, offset: "imageRendering", len: 0, typ: NTI33554440, name: "imageRendering", sons: null}, +{kind: 1, offset: "inlineSize", len: 0, typ: NTI33554440, name: "inlineSize", sons: null}, +{kind: 1, offset: "inset", len: 0, typ: NTI33554440, name: "inset", sons: null}, +{kind: 1, offset: "insetBlock", len: 0, typ: NTI33554440, name: "insetBlock", sons: null}, +{kind: 1, offset: "insetBlockEnd", len: 0, typ: NTI33554440, name: "insetBlockEnd", sons: null}, +{kind: 1, offset: "insetBlockStart", len: 0, typ: NTI33554440, name: "insetBlockStart", sons: null}, +{kind: 1, offset: "insetInline", len: 0, typ: NTI33554440, name: "insetInline", sons: null}, +{kind: 1, offset: "insetInlineEnd", len: 0, typ: NTI33554440, name: "insetInlineEnd", sons: null}, +{kind: 1, offset: "insetInlineStart", len: 0, typ: NTI33554440, name: "insetInlineStart", sons: null}, +{kind: 1, offset: "isolation", len: 0, typ: NTI33554440, name: "isolation", sons: null}, +{kind: 1, offset: "justifyContent", len: 0, typ: NTI33554440, name: "justifyContent", sons: null}, +{kind: 1, offset: "justifyItems", len: 0, typ: NTI33554440, name: "justifyItems", sons: null}, +{kind: 1, offset: "justifySelf", len: 0, typ: NTI33554440, name: "justifySelf", sons: null}, +{kind: 1, offset: "left", len: 0, typ: NTI33554440, name: "left", sons: null}, +{kind: 1, offset: "letterSpacing", len: 0, typ: NTI33554440, name: "letterSpacing", sons: null}, +{kind: 1, offset: "lineBreak", len: 0, typ: NTI33554440, name: "lineBreak", sons: null}, +{kind: 1, offset: "lineHeight", len: 0, typ: NTI33554440, name: "lineHeight", sons: null}, +{kind: 1, offset: "listStyle", len: 0, typ: NTI33554440, name: "listStyle", sons: null}, +{kind: 1, offset: "listStyleImage", len: 0, typ: NTI33554440, name: "listStyleImage", sons: null}, +{kind: 1, offset: "listStylePosition", len: 0, typ: NTI33554440, name: "listStylePosition", sons: null}, +{kind: 1, offset: "listStyleType", len: 0, typ: NTI33554440, name: "listStyleType", sons: null}, +{kind: 1, offset: "margin", len: 0, typ: NTI33554440, name: "margin", sons: null}, +{kind: 1, offset: "marginBlock", len: 0, typ: NTI33554440, name: "marginBlock", sons: null}, +{kind: 1, offset: "marginBlockEnd", len: 0, typ: NTI33554440, name: "marginBlockEnd", sons: null}, +{kind: 1, offset: "marginBlockStart", len: 0, typ: NTI33554440, name: "marginBlockStart", sons: null}, +{kind: 1, offset: "marginBottom", len: 0, typ: NTI33554440, name: "marginBottom", sons: null}, +{kind: 1, offset: "marginInline", len: 0, typ: NTI33554440, name: "marginInline", sons: null}, +{kind: 1, offset: "marginInlineEnd", len: 0, typ: NTI33554440, name: "marginInlineEnd", sons: null}, +{kind: 1, offset: "marginInlineStart", len: 0, typ: NTI33554440, name: "marginInlineStart", sons: null}, +{kind: 1, offset: "marginLeft", len: 0, typ: NTI33554440, name: "marginLeft", sons: null}, +{kind: 1, offset: "marginRight", len: 0, typ: NTI33554440, name: "marginRight", sons: null}, +{kind: 1, offset: "marginTop", len: 0, typ: NTI33554440, name: "marginTop", sons: null}, +{kind: 1, offset: "mask", len: 0, typ: NTI33554440, name: "mask", sons: null}, +{kind: 1, offset: "maskBorder", len: 0, typ: NTI33554440, name: "maskBorder", sons: null}, +{kind: 1, offset: "maskBorderMode", len: 0, typ: NTI33554440, name: "maskBorderMode", sons: null}, +{kind: 1, offset: "maskBorderOutset", len: 0, typ: NTI33554440, name: "maskBorderOutset", sons: null}, +{kind: 1, offset: "maskBorderRepeat", len: 0, typ: NTI33554440, name: "maskBorderRepeat", sons: null}, +{kind: 1, offset: "maskBorderSlice", len: 0, typ: NTI33554440, name: "maskBorderSlice", sons: null}, +{kind: 1, offset: "maskBorderSource", len: 0, typ: NTI33554440, name: "maskBorderSource", sons: null}, +{kind: 1, offset: "maskBorderWidth", len: 0, typ: NTI33554440, name: "maskBorderWidth", sons: null}, +{kind: 1, offset: "maskClip", len: 0, typ: NTI33554440, name: "maskClip", sons: null}, +{kind: 1, offset: "maskComposite", len: 0, typ: NTI33554440, name: "maskComposite", sons: null}, +{kind: 1, offset: "maskImage", len: 0, typ: NTI33554440, name: "maskImage", sons: null}, +{kind: 1, offset: "maskMode", len: 0, typ: NTI33554440, name: "maskMode", sons: null}, +{kind: 1, offset: "maskOrigin", len: 0, typ: NTI33554440, name: "maskOrigin", sons: null}, +{kind: 1, offset: "maskPosition", len: 0, typ: NTI33554440, name: "maskPosition", sons: null}, +{kind: 1, offset: "maskRepeat", len: 0, typ: NTI33554440, name: "maskRepeat", sons: null}, +{kind: 1, offset: "maskSize", len: 0, typ: NTI33554440, name: "maskSize", sons: null}, +{kind: 1, offset: "maskType", len: 0, typ: NTI33554440, name: "maskType", sons: null}, +{kind: 1, offset: "maxBlockSize", len: 0, typ: NTI33554440, name: "maxBlockSize", sons: null}, +{kind: 1, offset: "maxHeight", len: 0, typ: NTI33554440, name: "maxHeight", sons: null}, +{kind: 1, offset: "maxInlineSize", len: 0, typ: NTI33554440, name: "maxInlineSize", sons: null}, +{kind: 1, offset: "maxWidth", len: 0, typ: NTI33554440, name: "maxWidth", sons: null}, +{kind: 1, offset: "minBlockSize", len: 0, typ: NTI33554440, name: "minBlockSize", sons: null}, +{kind: 1, offset: "minHeight", len: 0, typ: NTI33554440, name: "minHeight", sons: null}, +{kind: 1, offset: "minInlineSize", len: 0, typ: NTI33554440, name: "minInlineSize", sons: null}, +{kind: 1, offset: "minWidth", len: 0, typ: NTI33554440, name: "minWidth", sons: null}, +{kind: 1, offset: "mixBlendMode", len: 0, typ: NTI33554440, name: "mixBlendMode", sons: null}, +{kind: 1, offset: "objectFit", len: 0, typ: NTI33554440, name: "objectFit", sons: null}, +{kind: 1, offset: "objectPosition", len: 0, typ: NTI33554440, name: "objectPosition", sons: null}, +{kind: 1, offset: "offset", len: 0, typ: NTI33554440, name: "offset", sons: null}, +{kind: 1, offset: "offsetAnchor", len: 0, typ: NTI33554440, name: "offsetAnchor", sons: null}, +{kind: 1, offset: "offsetDistance", len: 0, typ: NTI33554440, name: "offsetDistance", sons: null}, +{kind: 1, offset: "offsetPath", len: 0, typ: NTI33554440, name: "offsetPath", sons: null}, +{kind: 1, offset: "offsetRotate", len: 0, typ: NTI33554440, name: "offsetRotate", sons: null}, +{kind: 1, offset: "opacity", len: 0, typ: NTI33554440, name: "opacity", sons: null}, +{kind: 1, offset: "order", len: 0, typ: NTI33554440, name: "order", sons: null}, +{kind: 1, offset: "orphans", len: 0, typ: NTI33554440, name: "orphans", sons: null}, +{kind: 1, offset: "outline", len: 0, typ: NTI33554440, name: "outline", sons: null}, +{kind: 1, offset: "outlineColor", len: 0, typ: NTI33554440, name: "outlineColor", sons: null}, +{kind: 1, offset: "outlineOffset", len: 0, typ: NTI33554440, name: "outlineOffset", sons: null}, +{kind: 1, offset: "outlineStyle", len: 0, typ: NTI33554440, name: "outlineStyle", sons: null}, +{kind: 1, offset: "outlineWidth", len: 0, typ: NTI33554440, name: "outlineWidth", sons: null}, +{kind: 1, offset: "overflow", len: 0, typ: NTI33554440, name: "overflow", sons: null}, +{kind: 1, offset: "overflowAnchor", len: 0, typ: NTI33554440, name: "overflowAnchor", sons: null}, +{kind: 1, offset: "overflowBlock", len: 0, typ: NTI33554440, name: "overflowBlock", sons: null}, +{kind: 1, offset: "overflowInline", len: 0, typ: NTI33554440, name: "overflowInline", sons: null}, +{kind: 1, offset: "overflowWrap", len: 0, typ: NTI33554440, name: "overflowWrap", sons: null}, +{kind: 1, offset: "overflowX", len: 0, typ: NTI33554440, name: "overflowX", sons: null}, +{kind: 1, offset: "overflowY", len: 0, typ: NTI33554440, name: "overflowY", sons: null}, +{kind: 1, offset: "overscrollBehavior", len: 0, typ: NTI33554440, name: "overscrollBehavior", sons: null}, +{kind: 1, offset: "overscrollBehaviorBlock", len: 0, typ: NTI33554440, name: "overscrollBehaviorBlock", sons: null}, +{kind: 1, offset: "overscrollBehaviorInline", len: 0, typ: NTI33554440, name: "overscrollBehaviorInline", sons: null}, +{kind: 1, offset: "overscrollBehaviorX", len: 0, typ: NTI33554440, name: "overscrollBehaviorX", sons: null}, +{kind: 1, offset: "overscrollBehaviorY", len: 0, typ: NTI33554440, name: "overscrollBehaviorY", sons: null}, +{kind: 1, offset: "padding", len: 0, typ: NTI33554440, name: "padding", sons: null}, +{kind: 1, offset: "paddingBlock", len: 0, typ: NTI33554440, name: "paddingBlock", sons: null}, +{kind: 1, offset: "paddingBlockEnd", len: 0, typ: NTI33554440, name: "paddingBlockEnd", sons: null}, +{kind: 1, offset: "paddingBlockStart", len: 0, typ: NTI33554440, name: "paddingBlockStart", sons: null}, +{kind: 1, offset: "paddingBottom", len: 0, typ: NTI33554440, name: "paddingBottom", sons: null}, +{kind: 1, offset: "paddingInline", len: 0, typ: NTI33554440, name: "paddingInline", sons: null}, +{kind: 1, offset: "paddingInlineEnd", len: 0, typ: NTI33554440, name: "paddingInlineEnd", sons: null}, +{kind: 1, offset: "paddingInlineStart", len: 0, typ: NTI33554440, name: "paddingInlineStart", sons: null}, +{kind: 1, offset: "paddingLeft", len: 0, typ: NTI33554440, name: "paddingLeft", sons: null}, +{kind: 1, offset: "paddingRight", len: 0, typ: NTI33554440, name: "paddingRight", sons: null}, +{kind: 1, offset: "paddingTop", len: 0, typ: NTI33554440, name: "paddingTop", sons: null}, +{kind: 1, offset: "pageBreakAfter", len: 0, typ: NTI33554440, name: "pageBreakAfter", sons: null}, +{kind: 1, offset: "pageBreakBefore", len: 0, typ: NTI33554440, name: "pageBreakBefore", sons: null}, +{kind: 1, offset: "pageBreakInside", len: 0, typ: NTI33554440, name: "pageBreakInside", sons: null}, +{kind: 1, offset: "paintOrder", len: 0, typ: NTI33554440, name: "paintOrder", sons: null}, +{kind: 1, offset: "perspective", len: 0, typ: NTI33554440, name: "perspective", sons: null}, +{kind: 1, offset: "perspectiveOrigin", len: 0, typ: NTI33554440, name: "perspectiveOrigin", sons: null}, +{kind: 1, offset: "placeContent", len: 0, typ: NTI33554440, name: "placeContent", sons: null}, +{kind: 1, offset: "placeItems", len: 0, typ: NTI33554440, name: "placeItems", sons: null}, +{kind: 1, offset: "placeSelf", len: 0, typ: NTI33554440, name: "placeSelf", sons: null}, +{kind: 1, offset: "pointerEvents", len: 0, typ: NTI33554440, name: "pointerEvents", sons: null}, +{kind: 1, offset: "position", len: 0, typ: NTI33554440, name: "position", sons: null}, +{kind: 1, offset: "quotes", len: 0, typ: NTI33554440, name: "quotes", sons: null}, +{kind: 1, offset: "resize", len: 0, typ: NTI33554440, name: "resize", sons: null}, +{kind: 1, offset: "right", len: 0, typ: NTI33554440, name: "right", sons: null}, +{kind: 1, offset: "rotate", len: 0, typ: NTI33554440, name: "rotate", sons: null}, +{kind: 1, offset: "rowGap", len: 0, typ: NTI33554440, name: "rowGap", sons: null}, +{kind: 1, offset: "scale", len: 0, typ: NTI33554440, name: "scale", sons: null}, +{kind: 1, offset: "scrollBehavior", len: 0, typ: NTI33554440, name: "scrollBehavior", sons: null}, +{kind: 1, offset: "scrollMargin", len: 0, typ: NTI33554440, name: "scrollMargin", sons: null}, +{kind: 1, offset: "scrollMarginBlock", len: 0, typ: NTI33554440, name: "scrollMarginBlock", sons: null}, +{kind: 1, offset: "scrollMarginBlockEnd", len: 0, typ: NTI33554440, name: "scrollMarginBlockEnd", sons: null}, +{kind: 1, offset: "scrollMarginBlockStart", len: 0, typ: NTI33554440, name: "scrollMarginBlockStart", sons: null}, +{kind: 1, offset: "scrollMarginBottom", len: 0, typ: NTI33554440, name: "scrollMarginBottom", sons: null}, +{kind: 1, offset: "scrollMarginInline", len: 0, typ: NTI33554440, name: "scrollMarginInline", sons: null}, +{kind: 1, offset: "scrollMarginInlineEnd", len: 0, typ: NTI33554440, name: "scrollMarginInlineEnd", sons: null}, +{kind: 1, offset: "scrollMarginInlineStart", len: 0, typ: NTI33554440, name: "scrollMarginInlineStart", sons: null}, +{kind: 1, offset: "scrollMarginLeft", len: 0, typ: NTI33554440, name: "scrollMarginLeft", sons: null}, +{kind: 1, offset: "scrollMarginRight", len: 0, typ: NTI33554440, name: "scrollMarginRight", sons: null}, +{kind: 1, offset: "scrollMarginTop", len: 0, typ: NTI33554440, name: "scrollMarginTop", sons: null}, +{kind: 1, offset: "scrollPadding", len: 0, typ: NTI33554440, name: "scrollPadding", sons: null}, +{kind: 1, offset: "scrollPaddingBlock", len: 0, typ: NTI33554440, name: "scrollPaddingBlock", sons: null}, +{kind: 1, offset: "scrollPaddingBlockEnd", len: 0, typ: NTI33554440, name: "scrollPaddingBlockEnd", sons: null}, +{kind: 1, offset: "scrollPaddingBlockStart", len: 0, typ: NTI33554440, name: "scrollPaddingBlockStart", sons: null}, +{kind: 1, offset: "scrollPaddingBottom", len: 0, typ: NTI33554440, name: "scrollPaddingBottom", sons: null}, +{kind: 1, offset: "scrollPaddingInline", len: 0, typ: NTI33554440, name: "scrollPaddingInline", sons: null}, +{kind: 1, offset: "scrollPaddingInlineEnd", len: 0, typ: NTI33554440, name: "scrollPaddingInlineEnd", sons: null}, +{kind: 1, offset: "scrollPaddingInlineStart", len: 0, typ: NTI33554440, name: "scrollPaddingInlineStart", sons: null}, +{kind: 1, offset: "scrollPaddingLeft", len: 0, typ: NTI33554440, name: "scrollPaddingLeft", sons: null}, +{kind: 1, offset: "scrollPaddingRight", len: 0, typ: NTI33554440, name: "scrollPaddingRight", sons: null}, +{kind: 1, offset: "scrollPaddingTop", len: 0, typ: NTI33554440, name: "scrollPaddingTop", sons: null}, +{kind: 1, offset: "scrollSnapAlign", len: 0, typ: NTI33554440, name: "scrollSnapAlign", sons: null}, +{kind: 1, offset: "scrollSnapStop", len: 0, typ: NTI33554440, name: "scrollSnapStop", sons: null}, +{kind: 1, offset: "scrollSnapType", len: 0, typ: NTI33554440, name: "scrollSnapType", sons: null}, +{kind: 1, offset: "scrollbar3dLightColor", len: 0, typ: NTI33554440, name: "scrollbar3dLightColor", sons: null}, +{kind: 1, offset: "scrollbarArrowColor", len: 0, typ: NTI33554440, name: "scrollbarArrowColor", sons: null}, +{kind: 1, offset: "scrollbarBaseColor", len: 0, typ: NTI33554440, name: "scrollbarBaseColor", sons: null}, +{kind: 1, offset: "scrollbarColor", len: 0, typ: NTI33554440, name: "scrollbarColor", sons: null}, +{kind: 1, offset: "scrollbarDarkshadowColor", len: 0, typ: NTI33554440, name: "scrollbarDarkshadowColor", sons: null}, +{kind: 1, offset: "scrollbarFaceColor", len: 0, typ: NTI33554440, name: "scrollbarFaceColor", sons: null}, +{kind: 1, offset: "scrollbarHighlightColor", len: 0, typ: NTI33554440, name: "scrollbarHighlightColor", sons: null}, +{kind: 1, offset: "scrollbarShadowColor", len: 0, typ: NTI33554440, name: "scrollbarShadowColor", sons: null}, +{kind: 1, offset: "scrollbarTrackColor", len: 0, typ: NTI33554440, name: "scrollbarTrackColor", sons: null}, +{kind: 1, offset: "scrollbarWidth", len: 0, typ: NTI33554440, name: "scrollbarWidth", sons: null}, +{kind: 1, offset: "shapeImageThreshold", len: 0, typ: NTI33554440, name: "shapeImageThreshold", sons: null}, +{kind: 1, offset: "shapeMargin", len: 0, typ: NTI33554440, name: "shapeMargin", sons: null}, +{kind: 1, offset: "shapeOutside", len: 0, typ: NTI33554440, name: "shapeOutside", sons: null}, +{kind: 1, offset: "tabSize", len: 0, typ: NTI33554440, name: "tabSize", sons: null}, +{kind: 1, offset: "tableLayout", len: 0, typ: NTI33554440, name: "tableLayout", sons: null}, +{kind: 1, offset: "textAlign", len: 0, typ: NTI33554440, name: "textAlign", sons: null}, +{kind: 1, offset: "textAlignLast", len: 0, typ: NTI33554440, name: "textAlignLast", sons: null}, +{kind: 1, offset: "textCombineUpright", len: 0, typ: NTI33554440, name: "textCombineUpright", sons: null}, +{kind: 1, offset: "textDecoration", len: 0, typ: NTI33554440, name: "textDecoration", sons: null}, +{kind: 1, offset: "textDecorationColor", len: 0, typ: NTI33554440, name: "textDecorationColor", sons: null}, +{kind: 1, offset: "textDecorationLine", len: 0, typ: NTI33554440, name: "textDecorationLine", sons: null}, +{kind: 1, offset: "textDecorationSkipInk", len: 0, typ: NTI33554440, name: "textDecorationSkipInk", sons: null}, +{kind: 1, offset: "textDecorationStyle", len: 0, typ: NTI33554440, name: "textDecorationStyle", sons: null}, +{kind: 1, offset: "textDecorationThickness", len: 0, typ: NTI33554440, name: "textDecorationThickness", sons: null}, +{kind: 1, offset: "textEmphasis", len: 0, typ: NTI33554440, name: "textEmphasis", sons: null}, +{kind: 1, offset: "textEmphasisColor", len: 0, typ: NTI33554440, name: "textEmphasisColor", sons: null}, +{kind: 1, offset: "textEmphasisPosition", len: 0, typ: NTI33554440, name: "textEmphasisPosition", sons: null}, +{kind: 1, offset: "textEmphasisStyle", len: 0, typ: NTI33554440, name: "textEmphasisStyle", sons: null}, +{kind: 1, offset: "textIndent", len: 0, typ: NTI33554440, name: "textIndent", sons: null}, +{kind: 1, offset: "textJustify", len: 0, typ: NTI33554440, name: "textJustify", sons: null}, +{kind: 1, offset: "textOrientation", len: 0, typ: NTI33554440, name: "textOrientation", sons: null}, +{kind: 1, offset: "textOverflow", len: 0, typ: NTI33554440, name: "textOverflow", sons: null}, +{kind: 1, offset: "textRendering", len: 0, typ: NTI33554440, name: "textRendering", sons: null}, +{kind: 1, offset: "textShadow", len: 0, typ: NTI33554440, name: "textShadow", sons: null}, +{kind: 1, offset: "textTransform", len: 0, typ: NTI33554440, name: "textTransform", sons: null}, +{kind: 1, offset: "textUnderlineOffset", len: 0, typ: NTI33554440, name: "textUnderlineOffset", sons: null}, +{kind: 1, offset: "textUnderlinePosition", len: 0, typ: NTI33554440, name: "textUnderlinePosition", sons: null}, +{kind: 1, offset: "top", len: 0, typ: NTI33554440, name: "top", sons: null}, +{kind: 1, offset: "touchAction", len: 0, typ: NTI33554440, name: "touchAction", sons: null}, +{kind: 1, offset: "transform", len: 0, typ: NTI33554440, name: "transform", sons: null}, +{kind: 1, offset: "transformBox", len: 0, typ: NTI33554440, name: "transformBox", sons: null}, +{kind: 1, offset: "transformOrigin", len: 0, typ: NTI33554440, name: "transformOrigin", sons: null}, +{kind: 1, offset: "transformStyle", len: 0, typ: NTI33554440, name: "transformStyle", sons: null}, +{kind: 1, offset: "transition", len: 0, typ: NTI33554440, name: "transition", sons: null}, +{kind: 1, offset: "transitionDelay", len: 0, typ: NTI33554440, name: "transitionDelay", sons: null}, +{kind: 1, offset: "transitionDuration", len: 0, typ: NTI33554440, name: "transitionDuration", sons: null}, +{kind: 1, offset: "transitionProperty", len: 0, typ: NTI33554440, name: "transitionProperty", sons: null}, +{kind: 1, offset: "transitionTimingFunction", len: 0, typ: NTI33554440, name: "transitionTimingFunction", sons: null}, +{kind: 1, offset: "translate", len: 0, typ: NTI33554440, name: "translate", sons: null}, +{kind: 1, offset: "unicodeBidi", len: 0, typ: NTI33554440, name: "unicodeBidi", sons: null}, +{kind: 1, offset: "verticalAlign", len: 0, typ: NTI33554440, name: "verticalAlign", sons: null}, +{kind: 1, offset: "visibility", len: 0, typ: NTI33554440, name: "visibility", sons: null}, +{kind: 1, offset: "whiteSpace", len: 0, typ: NTI33554440, name: "whiteSpace", sons: null}, +{kind: 1, offset: "widows", len: 0, typ: NTI33554440, name: "widows", sons: null}, +{kind: 1, offset: "width", len: 0, typ: NTI33554440, name: "width", sons: null}, +{kind: 1, offset: "willChange", len: 0, typ: NTI33554440, name: "willChange", sons: null}, +{kind: 1, offset: "wordBreak", len: 0, typ: NTI33554440, name: "wordBreak", sons: null}, +{kind: 1, offset: "wordSpacing", len: 0, typ: NTI33554440, name: "wordSpacing", sons: null}, +{kind: 1, offset: "writingMode", len: 0, typ: NTI33554440, name: "writingMode", sons: null}, +{kind: 1, offset: "zIndex", len: 0, typ: NTI33554440, name: "zIndex", sons: null}]}; +NTI620757041.node = NNI620757041; +NTI620757041.base = NTI33555083; +NTI620757040.base = NTI620757041; +var NNI620757013 = {kind: 2, len: 22, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "attributes", len: 0, typ: NTI620757133, name: "attributes", sons: null}, +{kind: 1, offset: "childNodes", len: 0, typ: NTI620757134, name: "childNodes", sons: null}, +{kind: 1, offset: "children", len: 0, typ: NTI620757135, name: "children", sons: null}, +{kind: 1, offset: "data", len: 0, typ: NTI33554440, name: "data", sons: null}, +{kind: 1, offset: "firstChild", len: 0, typ: NTI620757012, name: "firstChild", sons: null}, +{kind: 1, offset: "lastChild", len: 0, typ: NTI620757012, name: "lastChild", sons: null}, +{kind: 1, offset: "nextSibling", len: 0, typ: NTI620757012, name: "nextSibling", sons: null}, +{kind: 1, offset: "nodeName", len: 0, typ: NTI33554440, name: "nodeName", sons: null}, +{kind: 1, offset: "nodeType", len: 0, typ: NTI620757011, name: "nodeType", sons: null}, +{kind: 1, offset: "nodeValue", len: 0, typ: NTI33554440, name: "nodeValue", sons: null}, +{kind: 1, offset: "parentNode", len: 0, typ: NTI620757012, name: "parentNode", sons: null}, +{kind: 1, offset: "content", len: 0, typ: NTI620757012, name: "content", sons: null}, +{kind: 1, offset: "previousSibling", len: 0, typ: NTI620757012, name: "previousSibling", sons: null}, +{kind: 1, offset: "ownerDocument", len: 0, typ: NTI620757014, name: "ownerDocument", sons: null}, +{kind: 1, offset: "innerHTML", len: 0, typ: NTI33554440, name: "innerHTML", sons: null}, +{kind: 1, offset: "outerHTML", len: 0, typ: NTI33554440, name: "outerHTML", sons: null}, +{kind: 1, offset: "innerText", len: 0, typ: NTI33554440, name: "innerText", sons: null}, +{kind: 1, offset: "textContent", len: 0, typ: NTI33554440, name: "textContent", sons: null}, +{kind: 1, offset: "style", len: 0, typ: NTI620757040, name: "style", sons: null}, +{kind: 1, offset: "baseURI", len: 0, typ: NTI33554440, name: "baseURI", sons: null}, +{kind: 1, offset: "parentElement", len: 0, typ: NTI620757016, name: "parentElement", sons: null}, +{kind: 1, offset: "isConnected", len: 0, typ: NTI33554466, name: "isConnected", sons: null}]}; +NTI620757013.node = NNI620757013; +var NNI620756997 = {kind: 2, len: 24, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "onabort", len: 0, typ: NTI620757092, name: "onabort", sons: null}, +{kind: 1, offset: "onblur", len: 0, typ: NTI620757093, name: "onblur", sons: null}, +{kind: 1, offset: "onchange", len: 0, typ: NTI620757094, name: "onchange", sons: null}, +{kind: 1, offset: "onclick", len: 0, typ: NTI620757095, name: "onclick", sons: null}, +{kind: 1, offset: "ondblclick", len: 0, typ: NTI620757096, name: "ondblclick", sons: null}, +{kind: 1, offset: "onerror", len: 0, typ: NTI620757097, name: "onerror", sons: null}, +{kind: 1, offset: "onfocus", len: 0, typ: NTI620757098, name: "onfocus", sons: null}, +{kind: 1, offset: "onkeydown", len: 0, typ: NTI620757099, name: "onkeydown", sons: null}, +{kind: 1, offset: "onkeypress", len: 0, typ: NTI620757100, name: "onkeypress", sons: null}, +{kind: 1, offset: "onkeyup", len: 0, typ: NTI620757101, name: "onkeyup", sons: null}, +{kind: 1, offset: "onload", len: 0, typ: NTI620757102, name: "onload", sons: null}, +{kind: 1, offset: "onmousedown", len: 0, typ: NTI620757103, name: "onmousedown", sons: null}, +{kind: 1, offset: "onmousemove", len: 0, typ: NTI620757104, name: "onmousemove", sons: null}, +{kind: 1, offset: "onmouseout", len: 0, typ: NTI620757105, name: "onmouseout", sons: null}, +{kind: 1, offset: "onmouseover", len: 0, typ: NTI620757106, name: "onmouseover", sons: null}, +{kind: 1, offset: "onmouseup", len: 0, typ: NTI620757107, name: "onmouseup", sons: null}, +{kind: 1, offset: "onreset", len: 0, typ: NTI620757108, name: "onreset", sons: null}, +{kind: 1, offset: "onselect", len: 0, typ: NTI620757109, name: "onselect", sons: null}, +{kind: 1, offset: "onstorage", len: 0, typ: NTI620757110, name: "onstorage", sons: null}, +{kind: 1, offset: "onsubmit", len: 0, typ: NTI620757111, name: "onsubmit", sons: null}, +{kind: 1, offset: "onunload", len: 0, typ: NTI620757112, name: "onunload", sons: null}, +{kind: 1, offset: "onloadstart", len: 0, typ: NTI620757113, name: "onloadstart", sons: null}, +{kind: 1, offset: "onprogress", len: 0, typ: NTI620757114, name: "onprogress", sons: null}, +{kind: 1, offset: "onloadend", len: 0, typ: NTI620757115, name: "onloadend", sons: null}]}; +NTI620756997.node = NNI620756997; +NTI620756997.base = NTI33555083; +NTI620757013.base = NTI620756997; +NTI620757012.base = NTI620757013; +NTI620757436.base = NTI620757012; +NTI486539822.base = NTI33554440; +var NNI637534222 = {kind: 2, len: 2, offset: 0, typ: null, name: null, sons: [{kind: 1, offset: "Field0", len: 0, typ: NTI33554456, name: "Field0", sons: null}, +{kind: 1, offset: "Field1", len: 0, typ: NTI33554466, name: "Field1", sons: null}]}; +NTI637534222.node = NNI637534222; + +function makeNimstrLit(c_33556801) { + var result = []; + for (var i = 0; i < c_33556801.length; ++i) { + result[i] = c_33556801.charCodeAt(i); + } + return result; + + + +} + +function toJSStr(s_33556807) { + var Temporary5; + var Temporary7; + + var result_33556808 = null; + + var res_33556842 = newSeq_33556825((s_33556807).length); + var i_33556843 = 0; + var j_33556844 = 0; + Label1: do { + Label2: while (true) { + if (!(i_33556843 < (s_33556807).length)) break Label2; + var c_33556845 = s_33556807[i_33556843]; + if ((c_33556845 < 128)) { + res_33556842[j_33556844] = String.fromCharCode(c_33556845); + i_33556843 += 1; + } + else { + var helper_33556857 = newSeq_33556825(0); + Label3: do { + Label4: while (true) { + if (!true) break Label4; + var code_33556858 = c_33556845.toString(16); + if ((((code_33556858) == null ? 0 : (code_33556858).length) == 1)) { + helper_33556857.push("%0");; + } + else { + helper_33556857.push("%");; + } + + helper_33556857.push(code_33556858);; + i_33556843 += 1; + if (((s_33556807).length <= i_33556843)) Temporary5 = true; else { Temporary5 = (s_33556807[i_33556843] < 128); } if (Temporary5) { + break Label3; + } + + c_33556845 = s_33556807[i_33556843]; + } + } while (false); +++excHandler; + Temporary7 = framePtr; + try { + res_33556842[j_33556844] = decodeURIComponent(helper_33556857.join("")); +--excHandler; +} catch (EXCEPTION) { + var prevJSError = lastJSError; + lastJSError = EXCEPTION; + --excHandler; + framePtr = Temporary7; + res_33556842[j_33556844] = helper_33556857.join(""); + lastJSError = prevJSError; + } finally { + framePtr = Temporary7; + } + } + + j_33556844 += 1; + } + } while (false); + if (res_33556842.length < j_33556844) { for (var i = res_33556842.length ; i < j_33556844 ; ++i) res_33556842.push(null); } + else { res_33556842.length = j_33556844; }; + result_33556808 = res_33556842.join(""); + + return result_33556808; + +} + +function raiseException(e_33556667, ename_33556668) { + e_33556667.name = ename_33556668; + if ((excHandler == 0)) { + unhandledException(e_33556667); + } + + throw e_33556667; + + +} + +function addInt(a_33556940, b_33556941) { + var result = a_33556940 + b_33556941; + checkOverflowInt(result); + return result; + + + +} + +function mnewString(len_33556893) { + return new Array(len_33556893); + + + +} + +function chckRange(i_33557189, a_33557190, b_33557191) { + var Temporary1; + + var result_33557192 = 0; + + BeforeRet: do { + if (!(a_33557190 <= i_33557189)) Temporary1 = false; else { Temporary1 = (i_33557189 <= b_33557191); } if (Temporary1) { + result_33557192 = i_33557189; + break BeforeRet; + } + else { + raiseRangeError(); + } + + } while (false); + + return result_33557192; + +} + +function setConstr() { + 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; + + + +} +var ConstSet1 = setConstr(17, 16, 4, 18, 27, 19, 23, 22, 21); + +function nimCopy(dest_33557140, src_33557141, ti_33557142) { + var result_33557151 = null; + + switch (ti_33557142.kind) { + case 21: + case 22: + case 23: + case 5: + if (!(isFatPointer_33557131(ti_33557142))) { + result_33557151 = src_33557141; + } + else { + result_33557151 = [src_33557141[0], src_33557141[1]]; + } + + break; + case 19: + if (dest_33557140 === null || dest_33557140 === undefined) { + dest_33557140 = {}; + } + else { + for (var key in dest_33557140) { delete dest_33557140[key]; } + } + for (var key in src_33557141) { dest_33557140[key] = src_33557141[key]; } + result_33557151 = dest_33557140; + + break; + case 18: + case 17: + if (!((ti_33557142.base == null))) { + result_33557151 = nimCopy(dest_33557140, src_33557141, ti_33557142.base); + } + else { + if ((ti_33557142.kind == 17)) { + result_33557151 = (dest_33557140 === null || dest_33557140 === undefined) ? {m_type: ti_33557142} : dest_33557140; + } + else { + result_33557151 = (dest_33557140 === null || dest_33557140 === undefined) ? {} : dest_33557140; + } + } + nimCopyAux(result_33557151, src_33557141, ti_33557142.node); + break; + case 24: + case 4: + case 27: + case 16: + if (src_33557141 === null) { + result_33557151 = null; + } + else { + if (dest_33557140 === null || dest_33557140 === undefined || dest_33557140.length != src_33557141.length) { + dest_33557140 = new Array(src_33557141.length); + } + result_33557151 = dest_33557140; + for (var i = 0; i < src_33557141.length; ++i) { + result_33557151[i] = nimCopy(result_33557151[i], src_33557141[i], ti_33557142.base); + } + } + + break; + case 28: + if (src_33557141 !== null) { + result_33557151 = src_33557141.slice(0); + } + + break; + default: + result_33557151 = src_33557141; + break; + } + + return result_33557151; + +} + +function chckIndx(i_33557184, a_33557185, b_33557186) { + var Temporary1; + + var result_33557187 = 0; + + BeforeRet: do { + if (!(a_33557185 <= i_33557184)) Temporary1 = false; else { Temporary1 = (i_33557184 <= b_33557186); } if (Temporary1) { + result_33557187 = i_33557184; + break BeforeRet; + } + else { + raiseIndexError(i_33557184, a_33557185, b_33557186); + } + + } while (false); + + return result_33557187; + +} + +function subInt(a_33556944, b_33556945) { + var result = a_33556944 - b_33556945; + checkOverflowInt(result); + return result; + + + +} +var ConstSet2 = setConstr([65, 90]); +var ConstSet3 = setConstr(95, 32, 46); +var ConstSet4 = setConstr(95, 32, 46); + +function mulInt(a_33556948, b_33556949) { + var result = a_33556948 * b_33556949; + checkOverflowInt(result); + return result; + + + +} +var ConstSet5 = setConstr([97, 122]); +var ConstSet6 = setConstr([65, 90], [97, 122]); +var ConstSet7 = setConstr([97, 122]); +var ConstSet8 = setConstr([65, 90]); +var ConstSet9 = setConstr([65, 90], [97, 122]); + +function nimMax(a_33556998, b_33556999) { + var Temporary1; + + var result_33557000 = 0; + + BeforeRet: do { + if ((b_33556999 <= a_33556998)) { + Temporary1 = a_33556998; + } + else { + Temporary1 = b_33556999; + } + + result_33557000 = Temporary1; + break BeforeRet; + } while (false); + + return result_33557000; + +} + +function nimMin(a_33556994, b_33556995) { + var Temporary1; + + var result_33556996 = 0; + + BeforeRet: do { + if ((a_33556994 <= b_33556995)) { + Temporary1 = a_33556994; + } + else { + Temporary1 = b_33556995; + } + + result_33556996 = Temporary1; + break BeforeRet; + } while (false); + + return result_33556996; + +} + +function addChar(x_33557255, c_33557256) { + x_33557255.push(c_33557256); + + +} +if (!Math.trunc) { + Math.trunc = function(v) { + v = +v; + if (!isFinite(v)) return v; + return (v - v % 1) || (v < 0 ? -0 : v === 0 ? v : 0); + }; +} + +var alternative_486539840 = [null]; + +function add_33556419(x_33556420, x_33556420_Idx, y_33556421) { + if (x_33556420[x_33556420_Idx] === null) { x_33556420[x_33556420_Idx] = []; } + var off = x_33556420[x_33556420_Idx].length; + x_33556420[x_33556420_Idx].length += y_33556421.length; + for (var i = 0; i < y_33556421.length; ++i) { + x_33556420[x_33556420_Idx][off+i] = y_33556421.charCodeAt(i); + } + + + +} + +function newSeq_33556825(len_33556827) { + var result_33556828 = []; + + result_33556828 = new Array(len_33556827); for (var i = 0 ; i < len_33556827 ; ++i) { result_33556828[i] = null; } + return result_33556828; + +} + +function unhandledException(e_33556663) { + var buf_33556664 = [[]]; + if (!(((e_33556663.message).length == 0))) { + buf_33556664[0].push.apply(buf_33556664[0], makeNimstrLit("Error: unhandled exception: "));; + buf_33556664[0].push.apply(buf_33556664[0], e_33556663.message);; + } + else { + buf_33556664[0].push.apply(buf_33556664[0], makeNimstrLit("Error: unhandled exception"));; + } + + buf_33556664[0].push.apply(buf_33556664[0], makeNimstrLit(" ["));; + add_33556419(buf_33556664, 0, e_33556663.name); + buf_33556664[0].push.apply(buf_33556664[0], makeNimstrLit("]\x0A"));; + var cbuf_33556665 = toJSStr(buf_33556664[0]); + framePtr = null; + if (typeof(Error) !== "undefined") { + throw new Error(cbuf_33556665); + } + else { + throw cbuf_33556665; + } + + + +} + +function raiseOverflow() { + raiseException({message: makeNimstrLit("over- or underflow"), parent: null, m_type: NTI33555122, name: null, trace: [], up: null}, "OverflowDefect"); + + +} + +function checkOverflowInt(a_33556938) { + if (a_33556938 > 2147483647 || a_33556938 < -2147483648) raiseOverflow(); + + + +} + +function isWhitespace_486539572(text_486539573) { + return !/[^\s]/.test(text_486539573); + + + +} + +function isWhitespace_486539575(x_486539576) { + var Temporary1; + var Temporary2; + + var result_486539577 = false; + + if (!(x_486539576.nodeName == "#text")) Temporary2 = false; else { Temporary2 = isWhitespace_486539572(x_486539576.textContent); } if (Temporary2) Temporary1 = true; else { Temporary1 = (x_486539576.nodeName == "#comment"); } result_486539577 = Temporary1; + + return result_486539577; + +} + +function raiseRangeError() { + raiseException({message: makeNimstrLit("value out of range"), parent: null, m_type: NTI33555130, name: null, trace: [], up: null}, "RangeDefect"); + + +} + +function addChars_251658415(result_251658417, result_251658417_Idx, x_251658418, start_251658419, n_251658420) { + var old_251658421 = (result_251658417[result_251658417_Idx]).length; + (result_251658417[result_251658417_Idx].length = chckRange(addInt(old_251658421, n_251658420), 0, 2147483647)); + Label1: do { + var iHEX60gensym4_251658435 = 0; + var i_486539890 = 0; + Label2: do { + Label3: while (true) { + if (!(i_486539890 < n_251658420)) break Label3; + iHEX60gensym4_251658435 = i_486539890; + result_251658417[result_251658417_Idx][chckIndx(addInt(old_251658421, iHEX60gensym4_251658435), 0, (result_251658417[result_251658417_Idx]).length - 1)] = x_251658418.charCodeAt(chckIndx(addInt(start_251658419, iHEX60gensym4_251658435), 0, (x_251658418).length - 1)); + i_486539890 = addInt(i_486539890, 1); + } + } while (false); + } while (false); + + +} + +function addChars_251658411(result_251658413, result_251658413_Idx, x_251658414) { + addChars_251658415(result_251658413, result_251658413_Idx, x_251658414, 0, ((x_251658414) == null ? 0 : (x_251658414).length)); + + +} + +function addInt_251658436(result_251658437, result_251658437_Idx, x_251658438) { + addChars_251658411(result_251658437, result_251658437_Idx, ((x_251658438) + "")); + + +} + +function addInt_251658457(result_251658458, result_251658458_Idx, x_251658459) { + addInt_251658436(result_251658458, result_251658458_Idx, x_251658459); + + +} + +function HEX24_335544323(x_335544324) { + var result_335544325 = [[]]; + + addInt_251658457(result_335544325, 0, x_335544324); + + return result_335544325[0]; + +} + +function isFatPointer_33557131(ti_33557132) { + var result_33557133 = false; + + BeforeRet: do { + result_33557133 = !((ConstSet1[ti_33557132.base.kind] != undefined)); + break BeforeRet; + } while (false); + + return result_33557133; + +} + +function nimCopyAux(dest_33557144, src_33557145, n_33557146) { + switch (n_33557146.kind) { + case 0: + break; + case 1: + dest_33557144[n_33557146.offset] = nimCopy(dest_33557144[n_33557146.offset], src_33557145[n_33557146.offset], n_33557146.typ); + + break; + case 2: + for (var i = 0; i < n_33557146.sons.length; i++) { + nimCopyAux(dest_33557144, src_33557145, n_33557146.sons[i]); + } + + break; + case 3: + dest_33557144[n_33557146.offset] = nimCopy(dest_33557144[n_33557146.offset], src_33557145[n_33557146.offset], n_33557146.typ); + for (var i = 0; i < n_33557146.sons.length; ++i) { + nimCopyAux(dest_33557144, src_33557145, n_33557146.sons[i][1]); + } + + break; + } + + +} + +function raiseIndexError(i_33556754, a_33556755, b_33556756) { + var Temporary1; + + if ((b_33556756 < a_33556755)) { + Temporary1 = makeNimstrLit("index out of bounds, the container is empty"); + } + else { + Temporary1 = (makeNimstrLit("index ") || []).concat(HEX24_335544323(i_33556754) || [],makeNimstrLit(" not in ") || [],HEX24_335544323(a_33556755) || [],makeNimstrLit(" .. ") || [],HEX24_335544323(b_33556756) || []); + } + + raiseException({message: nimCopy(null, Temporary1, NTI33554439), parent: null, m_type: NTI33555128, name: null, trace: [], up: null}, "IndexDefect"); + + +} + +function toToc_486539578(x_486539579, father_486539580) { + var Temporary5; + var Temporary6; + var Temporary7; + var Temporary8; + var Temporary15; + + if ((x_486539579.nodeName == "UL")) { + var f_486539588 = {heading: null, kids: [], sortId: (father_486539580.kids).length, doSort: false}; + var i_486539589 = 0; + Label1: do { + Label2: while (true) { + if (!(i_486539589 < x_486539579.childNodes.length)) break Label2; + var nxt_486539590 = addInt(i_486539589, 1); + Label3: do { + Label4: while (true) { + if (!(nxt_486539590 < x_486539579.childNodes.length)) Temporary5 = false; else { Temporary5 = isWhitespace_486539575(x_486539579.childNodes[nxt_486539590]); } if (!Temporary5) break Label4; + nxt_486539590 = addInt(nxt_486539590, 1); + } + } while (false); + if (!(nxt_486539590 < x_486539579.childNodes.length)) Temporary8 = false; else { Temporary8 = (x_486539579.childNodes[i_486539589].nodeName == "LI"); } if (!Temporary8) Temporary7 = false; else { Temporary7 = (x_486539579.childNodes[i_486539589].childNodes.length == 1); } if (!Temporary7) Temporary6 = false; else { Temporary6 = (x_486539579.childNodes[nxt_486539590].nodeName == "UL"); } if (Temporary6) { + var e_486539602 = {heading: x_486539579.childNodes[i_486539589].childNodes[0], kids: [], sortId: (f_486539588.kids).length, doSort: false}; + var it_486539603 = x_486539579.childNodes[nxt_486539590]; + Label9: do { + var j_486539608 = 0; + var colontmp__486539869 = 0; + colontmp__486539869 = it_486539603.childNodes.length; + var i_486539870 = 0; + Label10: do { + Label11: while (true) { + if (!(i_486539870 < colontmp__486539869)) break Label11; + j_486539608 = i_486539870; + toToc_486539578(it_486539603.childNodes[j_486539608], e_486539602); + i_486539870 = addInt(i_486539870, 1); + } + } while (false); + } while (false); + f_486539588.kids.push(e_486539602);; + i_486539589 = addInt(nxt_486539590, 1); + } + else { + toToc_486539578(x_486539579.childNodes[i_486539589], f_486539588); + i_486539589 = addInt(i_486539589, 1); + } + + } + } while (false); + father_486539580.kids.push(f_486539588);; + } + else { + if (isWhitespace_486539575(x_486539579)) { + } + else { + if ((x_486539579.nodeName == "LI")) { + var idx_486539625 = []; + Label12: do { + var i_486539630 = 0; + var colontmp__486539873 = 0; + colontmp__486539873 = x_486539579.childNodes.length; + var i_486539874 = 0; + Label13: do { + Label14: while (true) { + if (!(i_486539874 < colontmp__486539873)) break Label14; + i_486539630 = i_486539874; + if (!(isWhitespace_486539575(x_486539579.childNodes[i_486539630]))) { + idx_486539625.push(i_486539630);; + } + + i_486539874 = addInt(i_486539874, 1); + } + } while (false); + } while (false); + if (!((idx_486539625).length == 2)) Temporary15 = false; else { Temporary15 = (x_486539579.childNodes[idx_486539625[chckIndx(1, 0, (idx_486539625).length - 1)]].nodeName == "UL"); } if (Temporary15) { + var e_486539646 = {heading: x_486539579.childNodes[idx_486539625[chckIndx(0, 0, (idx_486539625).length - 1)]], kids: [], sortId: (father_486539580.kids).length, doSort: false}; + var it_486539647 = x_486539579.childNodes[idx_486539625[chckIndx(1, 0, (idx_486539625).length - 1)]]; + Label16: do { + var j_486539652 = 0; + var colontmp__486539877 = 0; + colontmp__486539877 = it_486539647.childNodes.length; + var i_486539878 = 0; + Label17: do { + Label18: while (true) { + if (!(i_486539878 < colontmp__486539877)) break Label18; + j_486539652 = i_486539878; + toToc_486539578(it_486539647.childNodes[j_486539652], e_486539646); + i_486539878 = addInt(i_486539878, 1); + } + } while (false); + } while (false); + father_486539580.kids.push(e_486539646);; + } + else { + Label19: do { + var i_486539661 = 0; + var colontmp__486539881 = 0; + colontmp__486539881 = x_486539579.childNodes.length; + var i_486539882 = 0; + Label20: do { + Label21: while (true) { + if (!(i_486539882 < colontmp__486539881)) break Label21; + i_486539661 = i_486539882; + toToc_486539578(x_486539579.childNodes[i_486539661], father_486539580); + i_486539882 = addInt(i_486539882, 1); + } + } while (false); + } while (false); + } + + } + else { + father_486539580.kids.push({heading: x_486539579, kids: [], sortId: (father_486539580.kids).length, doSort: false});; + } + }} + + +} + +function extractItems_486539398(x_486539399, heading_486539400, items_486539401, items_486539401_Idx) { + var Temporary1; + + BeforeRet: do { + if ((x_486539399 == null)) { + break BeforeRet; + } + + if (!!((x_486539399.heading == null))) Temporary1 = false; else { Temporary1 = (x_486539399.heading.textContent == heading_486539400); } if (Temporary1) { + Label2: do { + var i_486539418 = 0; + var colontmp__486539893 = 0; + colontmp__486539893 = (x_486539399.kids).length; + var i_486539894 = 0; + Label3: do { + Label4: while (true) { + if (!(i_486539894 < colontmp__486539893)) break Label4; + i_486539418 = i_486539894; + items_486539401[items_486539401_Idx].push(x_486539399.kids[chckIndx(i_486539418, 0, (x_486539399.kids).length - 1)].heading);; + i_486539894 = addInt(i_486539894, 1); + } + } while (false); + } while (false); + } + else { + Label5: do { + var i_486539430 = 0; + var colontmp__486539897 = 0; + colontmp__486539897 = (x_486539399.kids).length; + var i_486539898 = 0; + Label6: do { + Label7: while (true) { + if (!(i_486539898 < colontmp__486539897)) break Label7; + i_486539430 = i_486539898; + var it_486539431 = x_486539399.kids[chckIndx(i_486539430, 0, (x_486539399.kids).length - 1)]; + extractItems_486539398(it_486539431, heading_486539400, items_486539401, items_486539401_Idx); + i_486539898 = addInt(i_486539898, 1); + } + } while (false); + } while (false); + } + + } while (false); + + +} + +function tree_486539271(tag_486539272, kids_486539273) { + var result_486539274 = null; + + result_486539274 = document.createElement(toJSStr(tag_486539272)); + Label1: do { + var k_486539287 = null; + var i_486539911 = 0; + Label2: do { + Label3: while (true) { + if (!(i_486539911 < (kids_486539273).length)) break Label3; + k_486539287 = kids_486539273[chckIndx(i_486539911, 0, (kids_486539273).length - 1)]; + result_486539274.appendChild(k_486539287); + i_486539911 = addInt(i_486539911, 1); + } + } while (false); + } while (false); + + return result_486539274; + +} + +function text_486539325(s_486539326) { + var result_486539327 = null; + + result_486539327 = document.createTextNode(s_486539326); + + return result_486539327; + +} + +function sysFatal_218103842(message_218103845) { + raiseException({message: nimCopy(null, message_218103845, NTI33554439), m_type: NTI33555124, parent: null, name: null, trace: [], up: null}, "AssertionDefect"); + + +} + +function raiseAssert_218103840(msg_218103841) { + sysFatal_218103842(msg_218103841); + + +} + +function failedAssertImpl_218103864(msg_218103865) { + raiseAssert_218103840(msg_218103865); + + +} + +function uncovered_486539709(x_486539710) { + var Temporary1; + var Temporary2; + + var result_486539711 = null; + + BeforeRet: do { + if (!((x_486539710.kids).length == 0)) Temporary1 = false; else { Temporary1 = !((x_486539710.heading == null)); } if (Temporary1) { + if (!(x_486539710.heading.hasOwnProperty('__karaxMarker__'))) { + Temporary2 = x_486539710; + } + else { + Temporary2 = null; + } + + result_486539711 = Temporary2; + break BeforeRet; + } + + result_486539711 = {heading: x_486539710.heading, kids: [], sortId: x_486539710.sortId, doSort: x_486539710.doSort}; + Label3: do { + var i_486539730 = 0; + var colontmp__486539918 = 0; + colontmp__486539918 = (x_486539710.kids).length; + var i_486539919 = 0; + Label4: do { + Label5: while (true) { + if (!(i_486539919 < colontmp__486539918)) break Label5; + i_486539730 = i_486539919; + var y_486539731 = uncovered_486539709(x_486539710.kids[chckIndx(i_486539730, 0, (x_486539710.kids).length - 1)]); + if (!((y_486539731 == null))) { + result_486539711.kids.push(y_486539731);; + } + + i_486539919 = addInt(i_486539919, 1); + } + } while (false); + } while (false); + if (((result_486539711.kids).length == 0)) { + result_486539711 = null; + } + + } while (false); + + return result_486539711; + +} + +function mergeTocs_486539743(orig_486539744, news_486539745) { + var result_486539746 = null; + + result_486539746 = uncovered_486539709(orig_486539744); + if ((result_486539746 == null)) { + result_486539746 = news_486539745; + } + else { + Label1: do { + var i_486539758 = 0; + var colontmp__486539914 = 0; + colontmp__486539914 = (news_486539745.kids).length; + var i_486539915 = 0; + Label2: do { + Label3: while (true) { + if (!(i_486539915 < colontmp__486539914)) break Label3; + i_486539758 = i_486539915; + result_486539746.kids.push(news_486539745.kids[chckIndx(i_486539758, 0, (news_486539745.kids).length - 1)]);; + i_486539915 = addInt(i_486539915, 1); + } + } while (false); + } while (false); + } + + + return result_486539746; + +} + +function buildToc_486539763(orig_486539764, types_486539765, procs_486539766) { + var Temporary7; + + var result_486539767 = null; + + var newStuff_486539772 = {heading: null, kids: [], doSort: true, sortId: 0}; + Label1: do { + var t_486539794 = null; + var i_486539906 = 0; + var L_486539907 = (types_486539765).length; + Label2: do { + Label3: while (true) { + if (!(i_486539906 < L_486539907)) break Label3; + t_486539794 = types_486539765[chckIndx(i_486539906, 0, (types_486539765).length - 1)]; + var c_486539799 = {heading: t_486539794.cloneNode(true), kids: [], doSort: true, sortId: 0}; + t_486539794.__karaxMarker__ = true; + Label4: do { + var p_486539803 = null; + var i_486539903 = 0; + var L_486539904 = (procs_486539766).length; + Label5: do { + Label6: while (true) { + if (!(i_486539903 < L_486539904)) break Label6; + p_486539803 = procs_486539766[chckIndx(i_486539903, 0, (procs_486539766).length - 1)]; + if (!(p_486539803.hasOwnProperty('__karaxMarker__'))) { + var xx_486539804 = p_486539803.parentNode.getElementsByClassName("attachedType"); + if (!((xx_486539804).length == 1)) Temporary7 = false; else { Temporary7 = (xx_486539804[chckIndx(0, 0, (xx_486539804).length - 1)].textContent == t_486539794.textContent); } if (Temporary7) { + var q_486539809 = tree_486539271(makeNimstrLit("A"), [text_486539325(p_486539803.title)]); + q_486539809.setAttribute("href", p_486539803.getAttribute("href")); + c_486539799.kids.push({heading: q_486539809, kids: [], sortId: 0, doSort: false});; + p_486539803.__karaxMarker__ = true; + } + + } + + i_486539903 = addInt(i_486539903, 1); + if (!(((procs_486539766).length == L_486539904))) { + failedAssertImpl_218103864(makeNimstrLit("iterators.nim(240, 11) `len(a) == L` the length of the seq changed while iterating over it")); + } + + } + } while (false); + } while (false); + newStuff_486539772.kids.push(c_486539799);; + i_486539906 = addInt(i_486539906, 1); + if (!(((types_486539765).length == L_486539907))) { + failedAssertImpl_218103864(makeNimstrLit("iterators.nim(240, 11) `len(a) == L` the length of the seq changed while iterating over it")); + } + + } + } while (false); + } while (false); + result_486539767 = mergeTocs_486539743(orig_486539764, newStuff_486539772); + + return result_486539767; + +} + +function add_486539315(parent_486539316, kid_486539317) { + var Temporary1; + var Temporary2; + + if (!(parent_486539316.nodeName == "TR")) Temporary1 = false; else { if ((kid_486539317.nodeName == "TD")) Temporary2 = true; else { Temporary2 = (kid_486539317.nodeName == "TH"); } Temporary1 = Temporary2; } if (Temporary1) { + var k_486539318 = document.createElement("TD"); + k_486539318.appendChild(kid_486539317); + parent_486539316.appendChild(k_486539318); + } + else { + parent_486539316.appendChild(kid_486539317); + } + + + +} + +function setClass_486539319(e_486539320, value_486539321) { + e_486539320.setAttribute("class", toJSStr(value_486539321)); + + +} + +function toHtml_486539441(x_486539442, isRoot_486539443) { + var Temporary1; + +function HEX3Aanonymous_486539461(a_486539462, b_486539463) { + var Temporary1; + + var result_486539464 = 0; + + BeforeRet: do { + if (!!((a_486539462.heading == null))) Temporary1 = false; else { Temporary1 = !((b_486539463.heading == null)); } if (Temporary1) { + var x_486539473 = a_486539462.heading.textContent; + var y_486539474 = b_486539463.heading.textContent; + if ((x_486539473 < y_486539474)) { + result_486539464 = -1; + break BeforeRet; + } + + if ((y_486539474 < x_486539473)) { + result_486539464 = 1; + break BeforeRet; + } + + result_486539464 = 0; + break BeforeRet; + } + else { + result_486539464 = subInt(a_486539462.sortId, b_486539463.sortId); + break BeforeRet; + } + + } while (false); + + return result_486539464; + + } + + var result_486539444 = null; + + BeforeRet: do { + if ((x_486539442 == null)) { + result_486539444 = null; + break BeforeRet; + } + + if (((x_486539442.kids).length == 0)) { + if ((x_486539442.heading == null)) { + result_486539444 = null; + break BeforeRet; + } + + result_486539444 = x_486539442.heading.cloneNode(true); + break BeforeRet; + } + + result_486539444 = tree_486539271(makeNimstrLit("DIV"), []); + if (!!((x_486539442.heading == null))) Temporary1 = false; else { Temporary1 = !(x_486539442.heading.hasOwnProperty('__karaxMarker__')); } if (Temporary1) { + add_486539315(result_486539444, x_486539442.heading.cloneNode(true)); + } + + var ul_486539460 = tree_486539271(makeNimstrLit("UL"), []); + if (isRoot_486539443) { + setClass_486539319(ul_486539460, makeNimstrLit("simple simple-toc")); + } + else { + setClass_486539319(ul_486539460, makeNimstrLit("simple")); + } + + if (x_486539442.doSort) { + x_486539442.kids.sort(HEX3Aanonymous_486539461); + } + + Label2: do { + var k_486539503 = null; + var i_486539923 = 0; + var L_486539924 = (x_486539442.kids).length; + Label3: do { + Label4: while (true) { + if (!(i_486539923 < L_486539924)) break Label4; + k_486539503 = x_486539442.kids[chckIndx(i_486539923, 0, (x_486539442.kids).length - 1)]; + var y_486539504 = toHtml_486539441(k_486539503, false); + if (!((y_486539504 == null))) { + add_486539315(ul_486539460, tree_486539271(makeNimstrLit("LI"), [y_486539504])); + } + + i_486539923 = addInt(i_486539923, 1); + if (!(((x_486539442.kids).length == L_486539924))) { + failedAssertImpl_218103864(makeNimstrLit("iterators.nim(240, 11) `len(a) == L` the length of the seq changed while iterating over it")); + } + + } + } while (false); + } while (false); + if (!((ul_486539460.childNodes.length == 0))) { + add_486539315(result_486539444, ul_486539460); + } + + if ((result_486539444.childNodes.length == 0)) { + result_486539444 = null; + } + + } while (false); + + return result_486539444; + +} + +function replaceById_486539330(id_486539331, newTree_486539332) { + var x_486539333 = document.getElementById(id_486539331); + x_486539333.parentNode.replaceChild(newTree_486539332, x_486539333); + newTree_486539332.id = id_486539331; + + +} + +function togglevis_486539841(d_486539842) { + if (d_486539842.style.display == 'none') + d_486539842.style.display = 'inline'; + else + d_486539842.style.display = 'none'; + + + +} + +function groupBy(value_486539844) { + var toc_486539845 = document.getElementById("toc-list"); + if ((alternative_486539840[0] == null)) { + var tt_486539853 = {heading: null, kids: [], sortId: 0, doSort: false}; + toToc_486539578(toc_486539845, tt_486539853); + tt_486539853 = tt_486539853.kids[chckIndx(0, 0, (tt_486539853.kids).length - 1)]; + var types_486539858 = [[]]; + var procs_486539863 = [[]]; + extractItems_486539398(tt_486539853, "Types", types_486539858, 0); + extractItems_486539398(tt_486539853, "Procs", procs_486539863, 0); + extractItems_486539398(tt_486539853, "Converters", procs_486539863, 0); + extractItems_486539398(tt_486539853, "Methods", procs_486539863, 0); + extractItems_486539398(tt_486539853, "Templates", procs_486539863, 0); + extractItems_486539398(tt_486539853, "Macros", procs_486539863, 0); + extractItems_486539398(tt_486539853, "Iterators", procs_486539863, 0); + var ntoc_486539864 = buildToc_486539763(tt_486539853, types_486539858[0], procs_486539863[0]); + var x_486539865 = toHtml_486539441(ntoc_486539864, true); + alternative_486539840[0] = tree_486539271(makeNimstrLit("DIV"), [x_486539865]); + } + + if ((value_486539844 == "type")) { + replaceById_486539330("tocRoot", alternative_486539840[0]); + } + else { + replaceById_486539330("tocRoot", tree_486539271(makeNimstrLit("DIV"), [])); + } + + togglevis_486539841(document.getElementById("toc-list")); + + +} +var db_486539926 = [[]]; +var contents_486539927 = [[]]; +var oldtoc_486540074 = [null]; +var timer_486540075 = [null]; + +function nsuToLowerAsciiChar(c_654311492) { + var result_654311493 = 0; + + if ((ConstSet2[c_654311492] != undefined)) { + result_654311493 = (c_654311492 ^ 32); + } + else { + result_654311493 = c_654311492; + } + + + return result_654311493; + +} + +function fuzzyMatch_637534224(pattern_637534225, str_637534226) { + var Temporary4; + var Temporary5; + var Temporary6; + var Temporary7; + var Temporary8; + + var result_637534229 = {Field0: 0, Field1: false}; + + var scoreState_637534230 = -100; + var headerMatched_637534231 = false; + var unmatchedLeadingCharCount_637534232 = 0; + var consecutiveMatchCount_637534233 = 0; + var strIndex_637534234 = 0; + var patIndex_637534235 = 0; + var score_637534236 = 0; + Label1: do { + Label2: while (true) { + if (!((strIndex_637534234 < ((str_637534226) == null ? 0 : (str_637534226).length)) && (patIndex_637534235 < ((pattern_637534225) == null ? 0 : (pattern_637534225).length)))) break Label2; + Label3: do { + var patternChar_637534239 = nsuToLowerAsciiChar(pattern_637534225.charCodeAt(chckIndx(patIndex_637534235, 0, (pattern_637534225).length - 1))); + var strChar_637534240 = nsuToLowerAsciiChar(str_637534226.charCodeAt(chckIndx(strIndex_637534234, 0, (str_637534226).length - 1))); + if ((ConstSet3[patternChar_637534239] != undefined)) { + patIndex_637534235 = addInt(patIndex_637534235, 1); + break Label3; + } + + if ((ConstSet4[strChar_637534240] != undefined)) { + strIndex_637534234 = addInt(strIndex_637534234, 1); + break Label3; + } + + if ((!(headerMatched_637534231) && (strChar_637534240 == 58))) { + headerMatched_637534231 = true; + scoreState_637534230 = -100; + score_637534236 = ((Math.floor((0.5 * score_637534236))) | 0); + patIndex_637534235 = 0; + strIndex_637534234 = addInt(strIndex_637534234, 1); + break Label3; + } + + if ((strChar_637534240 == patternChar_637534239)) { + switch (scoreState_637534230) { + case -100: + case 20: + scoreState_637534230 = 10; + break; + case 0: + scoreState_637534230 = 5; + score_637534236 = addInt(score_637534236, scoreState_637534230); + break; + case 10: + case 5: + consecutiveMatchCount_637534233 = addInt(consecutiveMatchCount_637534233, 1); + scoreState_637534230 = 5; + score_637534236 = addInt(score_637534236, mulInt(5, consecutiveMatchCount_637534233)); + if ((scoreState_637534230 == 10)) { + score_637534236 = addInt(score_637534236, 10); + } + + var onBoundary_637534292 = (patIndex_637534235 == ((pattern_637534225) == null ? -1 : (pattern_637534225).length - 1)); + if ((!(onBoundary_637534292) && (strIndex_637534234 < ((str_637534226) == null ? -1 : (str_637534226).length - 1)))) { + var nextPatternChar_637534293 = nsuToLowerAsciiChar(pattern_637534225.charCodeAt(chckIndx(addInt(patIndex_637534235, 1), 0, (pattern_637534225).length - 1))); + var nextStrChar_637534294 = nsuToLowerAsciiChar(str_637534226.charCodeAt(chckIndx(addInt(strIndex_637534234, 1), 0, (str_637534226).length - 1))); + if (!!((ConstSet5[nextStrChar_637534294] != undefined))) Temporary4 = false; else { Temporary4 = !((nextStrChar_637534294 == nextPatternChar_637534293)); } onBoundary_637534292 = Temporary4; + } + + if (onBoundary_637534292) { + scoreState_637534230 = 20; + score_637534236 = addInt(score_637534236, scoreState_637534230); + } + + break; + case -1: + case -3: + if (!((ConstSet6[str_637534226.charCodeAt(chckIndx(subInt(strIndex_637534234, 1), 0, (str_637534226).length - 1))] != undefined))) Temporary5 = true; else { if (!(ConstSet7[str_637534226.charCodeAt(chckIndx(subInt(strIndex_637534234, 1), 0, (str_637534226).length - 1))] != undefined)) Temporary6 = false; else { Temporary6 = (ConstSet8[str_637534226.charCodeAt(chckIndx(strIndex_637534234, 0, (str_637534226).length - 1))] != undefined); } Temporary5 = Temporary6; } var isLeadingChar_637534318 = Temporary5; + if (isLeadingChar_637534318) { + scoreState_637534230 = 10; + } + else { + scoreState_637534230 = 0; + score_637534236 = addInt(score_637534236, scoreState_637534230); + } + + break; + } + patIndex_637534235 = addInt(patIndex_637534235, 1); + } + else { + switch (scoreState_637534230) { + case -100: + scoreState_637534230 = -3; + score_637534236 = addInt(score_637534236, scoreState_637534230); + break; + case 5: + scoreState_637534230 = -1; + score_637534236 = addInt(score_637534236, scoreState_637534230); + consecutiveMatchCount_637534233 = 0; + break; + case -3: + if ((unmatchedLeadingCharCount_637534232 < 3)) { + scoreState_637534230 = -3; + score_637534236 = addInt(score_637534236, scoreState_637534230); + } + + unmatchedLeadingCharCount_637534232 = addInt(unmatchedLeadingCharCount_637534232, 1); + break; + default: + scoreState_637534230 = -1; + score_637534236 = addInt(score_637534236, scoreState_637534230); + break; + } + } + + strIndex_637534234 = addInt(strIndex_637534234, 1); + } while (false); + } + } while (false); + if (!(patIndex_637534235 == ((pattern_637534225) == null ? 0 : (pattern_637534225).length))) Temporary7 = false; else { if ((strIndex_637534234 == ((str_637534226) == null ? 0 : (str_637534226).length))) Temporary8 = true; else { Temporary8 = !((ConstSet9[str_637534226.charCodeAt(chckIndx(strIndex_637534234, 0, (str_637534226).length - 1))] != undefined)); } Temporary7 = Temporary8; } if (Temporary7) { + score_637534236 = addInt(score_637534236, 10); + } + + var colontmp__486540135 = nimMax(0, score_637534236); + var colontmp__486540136 = (0 < score_637534236); + result_637534229 = nimCopy(result_637534229, {Field0: colontmp__486540135, Field1: colontmp__486540136}, NTI637534222); + + return result_637534229; + +} + +function escapeCString_486539930(x_486539931, x_486539931_Idx) { + var s_486539932 = []; + Label1: do { + var c_486539933 = 0; + var iHEX60gensym6_486540139 = 0; + var nHEX60gensym6_486540140 = ((x_486539931[x_486539931_Idx]) == null ? 0 : (x_486539931[x_486539931_Idx]).length); + Label2: do { + Label3: while (true) { + if (!(iHEX60gensym6_486540139 < nHEX60gensym6_486540140)) break Label3; + c_486539933 = x_486539931[x_486539931_Idx].charCodeAt(chckIndx(iHEX60gensym6_486540139, 0, (x_486539931[x_486539931_Idx]).length - 1)); + switch (c_486539933) { + case 60: + s_486539932.push.apply(s_486539932, makeNimstrLit("<"));; + break; + case 62: + s_486539932.push.apply(s_486539932, makeNimstrLit(">"));; + break; + default: + addChar(s_486539932, c_486539933);; + break; + } + iHEX60gensym6_486540139 = addInt(iHEX60gensym6_486540139, 1); + } + } while (false); + } while (false); + x_486539931[x_486539931_Idx] = toJSStr(s_486539932); + + +} + +function text_486539322(s_486539323) { + var result_486539324 = null; + + result_486539324 = document.createTextNode(toJSStr(s_486539323)); + + return result_486539324; + +} + +function dosearch_486539934(value_486539935) { + +function HEX3Aanonymous_486539991(a_486539996, b_486539997) { + var result_486540002 = 0; + + result_486540002 = subInt(b_486539997["Field1"], a_486539996["Field1"]); + + return result_486540002; + + } + + var result_486539936 = null; + + if (((db_486539926[0]).length == 0)) { + var stuff_486539940 = null; + var request = new XMLHttpRequest(); + request.open("GET", "theindex.html", false); + request.send(null); + + var doc = document.implementation.createHTMLDocument("theindex"); + doc.documentElement.innerHTML = request.responseText; + + //parser=new DOMParser(); + //doc=parser.parseFromString("", "text/html"); + + stuff_486539940 = doc.documentElement; + + db_486539926[0] = nimCopy(null, stuff_486539940.getElementsByClassName("reference"), NTI620757436); + contents_486539927[0] = nimCopy(null, [], NTI486539822); + Label1: do { + var ahref_486539965 = null; + var i_486540120 = 0; + var L_486540121 = (db_486539926[0]).length; + Label2: do { + Label3: while (true) { + if (!(i_486540120 < L_486540121)) break Label3; + ahref_486539965 = db_486539926[0][chckIndx(i_486540120, 0, (db_486539926[0]).length - 1)]; + contents_486539927[0].push(ahref_486539965.getAttribute("data-doc-search-tag"));; + i_486540120 = addInt(i_486540120, 1); + if (!(((db_486539926[0]).length == L_486540121))) { + failedAssertImpl_218103864(makeNimstrLit("iterators.nim(240, 11) `len(a) == L` the length of the seq changed while iterating over it")); + } + + } + } while (false); + } while (false); + } + + var ul_486539970 = tree_486539271(makeNimstrLit("UL"), []); + result_486539936 = tree_486539271(makeNimstrLit("DIV"), []); + setClass_486539319(result_486539936, makeNimstrLit("search_results")); + var matches_486539975 = []; + Label4: do { + var i_486539983 = 0; + var colontmp__486540125 = 0; + colontmp__486540125 = (db_486539926[0]).length; + var i_486540126 = 0; + Label5: do { + Label6: while (true) { + if (!(i_486540126 < colontmp__486540125)) break Label6; + i_486539983 = i_486540126; + Label7: do { + var c_486539984 = contents_486539927[0][chckIndx(i_486539983, 0, (contents_486539927[0]).length - 1)]; + if (((c_486539984 == "Examples") || (c_486539984 == "PEG construction"))) { + break Label7; + } + + var colontmp__486540132 = fuzzyMatch_637534224(value_486539935, c_486539984); + var score_486539985 = colontmp__486540132["Field0"]; + var matched_486539986 = colontmp__486540132["Field1"]; + if (matched_486539986) { + matches_486539975.push({Field0: db_486539926[0][chckIndx(i_486539983, 0, (db_486539926[0]).length - 1)], Field1: score_486539985});; + } + + } while (false); + i_486540126 = addInt(i_486540126, 1); + } + } while (false); + } while (false); + matches_486539975.sort(HEX3Aanonymous_486539991); + Label8: do { + var i_486540019 = 0; + var colontmp__486540129 = 0; + colontmp__486540129 = nimMin((matches_486539975).length, 29); + var i_486540130 = 0; + Label9: do { + Label10: while (true) { + if (!(i_486540130 < colontmp__486540129)) break Label10; + i_486540019 = i_486540130; + matches_486539975[chckIndx(i_486540019, 0, (matches_486539975).length - 1)]["Field0"].innerHTML = matches_486539975[chckIndx(i_486540019, 0, (matches_486539975).length - 1)]["Field0"].getAttribute("data-doc-search-tag"); + escapeCString_486539930(matches_486539975[chckIndx(i_486540019, 0, (matches_486539975).length - 1)]["Field0"], "innerHTML"); + add_486539315(ul_486539970, tree_486539271(makeNimstrLit("LI"), [matches_486539975[chckIndx(i_486540019, 0, (matches_486539975).length - 1)]["Field0"]])); + i_486540130 = addInt(i_486540130, 1); + } + } while (false); + } while (false); + if ((ul_486539970.childNodes.length == 0)) { + add_486539315(result_486539936, tree_486539271(makeNimstrLit("B"), [text_486539322(makeNimstrLit("no search results"))])); + } + else { + add_486539315(result_486539936, tree_486539271(makeNimstrLit("B"), [text_486539322(makeNimstrLit("search results"))])); + add_486539315(result_486539936, ul_486539970); + } + + + return result_486539936; + +} + +function search() { + +function wrapper_486540086() { + var elem_486540087 = document.getElementById("searchInput"); + var value_486540088 = elem_486540087.value; + if (!((((value_486540088) == null ? 0 : (value_486540088).length) == 0))) { + if ((oldtoc_486540074[0] == null)) { + oldtoc_486540074[0] = document.getElementById("tocRoot"); + } + + var results_486540092 = dosearch_486539934(value_486540088); + replaceById_486539330("tocRoot", results_486540092); + } + else { + if (!((oldtoc_486540074[0] == null))) { + replaceById_486539330("tocRoot", oldtoc_486540074[0]); + } + } + + + } + + if (!((timer_486540075[0] == null))) { + clearTimeout(timer_486540075[0]); + } + + timer_486540075[0] = setTimeout(wrapper_486540086, 400); + + +} diff --git a/docs/fiber_orm.html b/docs/fiber_orm.html new file mode 100644 index 0000000..c727162 --- /dev/null +++ b/docs/fiber_orm.html @@ -0,0 +1,619 @@ + + + + + + + + + + + + + + + + + + +src/fiber_orm + + + + + + + + +
+
+

src/fiber_orm

+
+
+
+ +     Dark Mode +
+ +
+ Search: +
+
+ Group by: + +
+ + +
+   Source +  Edit + +
+
+ +

Lightweight ORM supporting the Postgres and SQLite databases in Nim. It supports a simple, opinionated model mapper to generate SQL queries based on Nim objects. It also includes a simple connection pooling implementation.

+

Fiber ORM is not intended to be a 100% all-cases-covered ORM that handles every potential data access pattern one might wish to implement. It is best thought of as a collection of common SQL generation patterns. It is intended to cover 90% of the common queries and functions one might write when implementing an SQL-based access layer. It is expected that there may be a few more complicated queries that need to be implemented to handle specific access patterns.

+

The simple mapping pattern provided by Fiber ORM also works well on top of databases that encapsulate data access logic in SQL with, for example, views.

+ +

Basic Usage

Consider a simple TODO list application that keeps track of TODO items as well as time logged against those items.

+ +

Example DB Schema

You might have a schema such as:

+
create extension if not exists "pgcrypto";
+
+create table todo_items columns (
+  id uuid not null primary key default gen_random_uuid(),
+  owner varchar not null,
+  summary varchar not null,
+  details varchar default null,
+  priority integer not null default 0,
+  related_todo_item_ids uuid[] not null default '{}'
+);
+
+create table time_entries columns (
+  id uuid not null primary key default gen_random_uuid(),
+  todo_item_id uuid not null references todo_items (id) on delete cascade,
+  start timestamp with timezone not null default current_timestamp,
+  stop timestamp with timezone default null,
+);
+

Example Model Definitions

Models may be defined as:

+
# models.nim
+import std/options, std/times
+import uuids
+
+type
+  TodoItem* = object
+    id*: UUID
+    owner*: string
+    summary*: string
+    details*: Option[string]
+    priority*: int
+    relatedTodoItemIds*: seq[UUID]
+  
+  TimeEntry* = object
+    id*: UUID
+    todoItemId*: Option[UUID]
+    start*: DateTime
+    stop*: Option[DateTime]
+

Example Fiber ORM Usage

Using Fiber ORM we can generate a data access layer with:

+
# db.nim
+import fiber_orm
+import ./models.nim
+
+type TodoDB* = DbConnPool
+
+proc initDb*(connString: string): TodoDB =
+  result = fiber_orm.initPool(
+    connect = proc(): DbConn = open("", "", "", connString),
+    poolSize = 20,
+    hardCap = false)
+
+
+generateProcsForModels(TodoDB, [TodoItem, TimeEntry])
+
+generateLookup(TodoDB, TimeEntry, @["todoItemId"])

This will generate the following procedures:

+
proc getTodoItem*(db: TodoDB, id: UUID): TodoItem;
+proc getAllTodoItems*(db: TodoDB): seq[TodoItem];
+proc createTodoItem*(db: TodoDB, rec: TodoItem): TodoItem;
+proc updateTodoItem*(db: TodoDB, rec: TodoItem): bool;
+proc deleteTodoItem*(db: TodoDB, rec: TodoItem): bool;
+proc deleteTodoItem*(db: TodoDB, id: UUID): bool;
+
+proc findTodoItemsWhere*(db: TodoDB, whereClause: string,
+  values: varargs[string, dbFormat]): seq[TodoItem];
+
+proc getTimeEntry*(db: TodoDB, id: UUID): TimeEntry;
+proc getAllTimeEntries*(db: TodoDB): seq[TimeEntry];
+proc createTimeEntry*(db: TodoDB, rec: TimeEntry): TimeEntry;
+proc updateTimeEntry*(db: TodoDB, rec: TimeEntry): bool;
+proc deleteTimeEntry*(db: TodoDB, rec: TimeEntry): bool;
+proc deleteTimeEntry*(db: TodoDB, id: UUID): bool;
+
+proc findTimeEntriesWhere*(db: TodoDB, whereClause: string,
+  values: varargs[string, dbFormat]): seq[TimeEntry];
+
+proc findTimeEntriesByTodoItemId(db: TodoDB, todoItemId: UUID): seq[TimeEntry];
+

Object-Relational Modeling

+

Model Class

Fiber ORM uses simple Nim objects and ref objects as model classes. Fiber ORM expects there to be one table for each model class.

+ +

Name Mapping

Fiber ORM uses snake_case for database identifiers (column names, table names, etc.) and camelCase for Nim identifiers. We automatically convert model names to and from table names (TodoItem <-> todo_items), as well as column names (userId <-> user_id).

+

Notice that table names are automatically pluralized from model class names. In the above example, you have:

+ + + +
Model ClassTable Name
TodoItemtodo_items
TimeEntrytime_entries

Because Nim is style-insensitive, you can generall refer to model classes and fields using snake_case, camelCase, or PascalCase in your code and expect Fiber ORM to be able to map the names to DB identifier names properly (though FiberORM will always use camelCase internally).

+

See the identNameToDb, dbNameToIdent, tableName and dbFormat procedures in the fiber module for details.

+ +

ID Field

Fiber ORM expects every model class to have a field named id, with a corresponding id column in the model table. This field must be either a string, integer, or UUID.

+

When creating a new record the id field will be omitted if it is empty (Option.isNone, UUID.isZero, value of 0, or only whitespace). This is intended to allow for cases like the example where the database may generate an ID when a new record is inserted. If a non-zero value is provided, the create call will include the id field in the INSERT query.

+

For example, to allow the database to create the id:

+
let item = TodoItem(
+  owner: "John Mann",
+  summary: "Create a grocery list.",
+  details: none[string](),
+  priority: 0,
+  relatedTodoItemIds: @[])
+
+let itemWithId = db.createTodoItem(item)
+echo $itemWithId.id # generated in the database

And to create it in code:

+
import uuids
+
+let item = TodoItem(
+  id: genUUID(),
+  owner: "John Mann",
+  summary: "Create a grocery list.",
+  details: none[string](),
+  priority: 0,
+  relatedTodoItemIds: @[])
+
+let itemInDb = db.createTodoItem(item)
+echo $itemInDb.id # will be the same as what was provided
+

Supported Data Types

The following Nim data types are supported by Fiber ORM:

+ + + + + + + + + + +
Nim TypePostgres TypeSQLite Type
stringvarchar
intinteger
floatdouble
boolboolean
DateTimetimestamp
seq[]array
UUIDuuid (pg)
Optionallows NULL [1]
JsonNodejsonb

+
  Note that this implies that all NULL-able fields should be typed as optional using Option[fieldType]. Conversely, any fields with non-optional types should also be constrained to be NOT NULL in the database schema. +
+
+ +

Database Object

Many of the Fiber ORM macros expect a database object type to be passed. In the example above the pool.DbConnPool object is used as database object type (aliased as TodoDB). This is the intended usage pattern, but anything can be passed as the database object type so long as there is a defined withConn template that provides an injected conn: DbConn object to the provided statement body.

+

For example, a valid database object implementation that opens a new connection for every request might look like this:

+
import std/db_postgres
+
+type TodoDB* = object
+  connString: string
+
+template withConn*(db: TodoDB, stmt: untyped): untyped =
+  let conn {.inject.} = open("", "", "", db.connString)
+  try: stmt
+  finally: close(conn)
+

See Also

fiber_orm/pool

+

+ +
+

Types

+
+
+
NotFoundError = object of CatchableError
+
+ + + Error type raised when no record matches a given ID +  Source +  Edit + +
+
+ +
+
+

Procs

+
+
+
proc createRecord[T](db: DbConn; rec: T): T
+
+ +

Create a new record. rec is expected to be a model class. The id field is only set if it is non-empty (see ID Field for details).

+

Returns the newly created record.

+ +  Source +  Edit + +
+
+
+
proc deleteRecord[T](db: DbConn; rec: T): bool
+
+ +Delete a record by id. +  Source +  Edit + +
+
+
+
proc initPool(connect: proc (): DbConn; poolSize = 10; hardCap = false;
+              healthCheckQuery = "SELECT \'true\' AS alive"): DbConnPool {.
+    ...raises: [Exception], tags: [RootEffect].}
+
+ +Initialize a new DbConnPool. See the initDb procedure in the Example Fiber ORM Usage for an example
  • connect must be a factory which creates a new DbConn.
  • +
  • poolSize sets the desired capacity of the connection pool.
  • +
  • hardCap defaults to false. When false, the pool can grow beyond the configured capacity, but will release connections down to the its capacity (no less than poolSize).

    +

    When true the pool will not create more than its configured capacity. It a connection is requested, none are free, and the pool is at capacity, this will result in an Error being raised.

    +
  • +
  • healthCheckQuery should be a simple and fast SQL query that the pool can use to test the liveliness of pooled connections.
  • +
+ +  Source +  Edit + +
+
+
+
proc updateRecord[T](db: DbConn; rec: T): bool
+
+ +Update a record by id. rec is expected to be a model class. +  Source +  Edit + +
+
+ +
+
+

Macros

+
+
+
macro generateLookup(dbType: type; modelType: type; fields: seq[string]): untyped
+
+ +Create a lookup procedure for a given set of field names. For example, given the TODO database demostrated above,
generateLookup(TodoDB, TodoItem, ["owner", "priority"])

will generate the following procedure:

+
proc findTodoItemsByOwnerAndPriority*(db: SampleDB,
+  owner: string, priority: int): seq[TodoItem]
+  Source +  Edit + +
+
+
+
macro generateProcsForFieldLookups(dbType: type; modelsAndFields: openArray[
+    tuple[t: type, fields: seq[string]]]): untyped
+
+ + +  Source +  Edit + +
+
+
+
macro generateProcsForModels(dbType: type; modelTypes: openArray[type]): untyped
+
+ +Generate all standard access procedures for the given model types. For a model class named TodoItem, this will generate the following procedures:
proc getTodoItem*(db: TodoDB, id: idType): TodoItem;
+proc getAllTodoItems*(db: TodoDB): TodoItem;
+proc createTodoItem*(db: TodoDB, rec: TodoItem): TodoItem;
+proc deleteTodoItem*(db: TodoDB, rec: TodoItem): bool;
+proc deleteTodoItem*(db: TodoDB, id: idType): bool;
+proc updateTodoItem*(db: TodoDB, rec: TodoItem): bool;
+
+proc findTodoItemsWhere*(
+  db: TodoDB, whereClause: string, values: varargs[string]): TodoItem;

dbType is expected to be some type that has a defined withConn procedure (see Database Object for details).

+ +  Source +  Edit + +
+
+ +
+
+

Templates

+
+
+
template deleteRecord(db: DbConn; modelType: type; id: typed): untyped
+
+ +Delete a record by id. +  Source +  Edit + +
+
+
+
template findRecordsBy(db: DbConn; modelType: type;
+                       lookups: seq[tuple[field: string, value: string]]): untyped
+
+ +Find all records matching the provided lookup values. +  Source +  Edit + +
+
+
+
template findRecordsWhere(db: DbConn; modelType: type; whereClause: string;
+                          values: varargs[string, dbFormat]): untyped
+
+ +Find all records matching a given WHERE clause. The number of elements in the values array must match the number of placeholders (?) in the provided WHERE clause. +  Source +  Edit + +
+
+
+
template getAllRecords(db: DbConn; modelType: type): untyped
+
+ +Fetch all records of the given type. +  Source +  Edit + +
+
+
+
template getRecord(db: DbConn; modelType: type; id: typed): untyped
+
+ +Fetch a record by id. +  Source +  Edit + +
+
+
+
template inTransaction(db: DbConnPool; body: untyped)
+
+ + +  Source +  Edit + +
+
+ +
+ + +
+
+ +
+ +
+
+
+ + + diff --git a/docs/fiber_orm.idx b/docs/fiber_orm.idx new file mode 100644 index 0000000..bfbe4c5 --- /dev/null +++ b/docs/fiber_orm.idx @@ -0,0 +1,25 @@ +NotFoundError fiber_orm.html#NotFoundError fiber_orm: NotFoundError +createRecord fiber_orm.html#createRecord,DbConn,T fiber_orm: createRecord[T](db: DbConn; rec: T): T +updateRecord fiber_orm.html#updateRecord,DbConn,T fiber_orm: updateRecord[T](db: DbConn; rec: T): bool +deleteRecord fiber_orm.html#deleteRecord.t,DbConn,type,typed fiber_orm: deleteRecord(db: DbConn; modelType: type; id: typed): untyped +deleteRecord fiber_orm.html#deleteRecord,DbConn,T fiber_orm: deleteRecord[T](db: DbConn; rec: T): bool +getRecord fiber_orm.html#getRecord.t,DbConn,type,typed fiber_orm: getRecord(db: DbConn; modelType: type; id: typed): untyped +findRecordsWhere fiber_orm.html#findRecordsWhere.t,DbConn,type,string,varargs[string,dbFormat] fiber_orm: findRecordsWhere(db: DbConn; modelType: type; whereClause: string;\n values: varargs[string, dbFormat]): untyped +getAllRecords fiber_orm.html#getAllRecords.t,DbConn,type fiber_orm: getAllRecords(db: DbConn; modelType: type): untyped +findRecordsBy fiber_orm.html#findRecordsBy.t,DbConn,type,seq[tuple[string,string]] fiber_orm: findRecordsBy(db: DbConn; modelType: type;\n lookups: seq[tuple[field: string, value: string]]): untyped +generateProcsForModels fiber_orm.html#generateProcsForModels.m,type,openArray[type] fiber_orm: generateProcsForModels(dbType: type; modelTypes: openArray[type]): untyped +generateLookup fiber_orm.html#generateLookup.m,type,type,seq[string] fiber_orm: generateLookup(dbType: type; modelType: type; fields: seq[string]): untyped +generateProcsForFieldLookups fiber_orm.html#generateProcsForFieldLookups.m,type,openArray[tuple[type,seq[string]]] fiber_orm: generateProcsForFieldLookups(dbType: type; modelsAndFields: openArray[\n tuple[t: type, fields: seq[string]]]): untyped +initPool fiber_orm.html#initPool,proc),int,string fiber_orm: initPool(connect: proc (): DbConn; poolSize = 10; hardCap = false;\n healthCheckQuery = "SELECT \'true\' AS alive"): DbConnPool +inTransaction fiber_orm.html#inTransaction.t,DbConnPool,untyped fiber_orm: inTransaction(db: DbConnPool; body: untyped) +Basic Usage fiber_orm.html#basic-usage Basic Usage +Example DB Schema fiber_orm.html#basic-usage-example-db-schema Example DB Schema +Example Model Definitions fiber_orm.html#basic-usage-example-model-definitions Example Model Definitions +Example Fiber ORM Usage fiber_orm.html#basic-usage-example-fiber-orm-usage Example Fiber ORM Usage +Object-Relational Modeling fiber_orm.html#objectminusrelational-modeling Object-Relational Modeling +Model Class fiber_orm.html#objectminusrelational-modeling-model-class Model Class +Name Mapping fiber_orm.html#model-class-name-mapping Name Mapping +ID Field fiber_orm.html#model-class-id-field ID Field +Supported Data Types fiber_orm.html#objectminusrelational-modeling-supported-data-types Supported Data Types +Database Object fiber_orm.html#database-object Database Object +See Also fiber_orm.html#see-also See Also diff --git a/docs/fiber_orm/pool.html b/docs/fiber_orm/pool.html new file mode 100644 index 0000000..e7f83dd --- /dev/null +++ b/docs/fiber_orm/pool.html @@ -0,0 +1,303 @@ + + + + + + + + + + + + + + + + + + +src/fiber_orm/pool + + + + + + + + +
+
+

src/fiber_orm/pool

+
+
+
+ +     Dark Mode +
+ +
+ Search: +
+
+ Group by: + +
+ + +
+   Source +  Edit + +
+
+ +

Simple database connection pooling implementation compatible with Fiber ORM.

+
+

Types

+
+
+
DbConnPool = ref object
+  conns: seq[PooledDbConn]
+  cfg: DbConnPoolConfig
+  lastId: int
+
+
+ +Database connection pool +  Source +  Edit + +
+
+
+
DbConnPoolConfig = object
+  connect*: () -> DbConn     ## Factory procedure to create a new DBConn
+  poolSize*: int             ## The pool capacity.
+  hardCap*: bool ## Is the pool capacity a hard cap?
+                 ## 
+                 ## When `false`, the pool can grow beyond the configured
+                 ## capacity, but will release connections down to the its
+                 ## capacity (no less than `poolSize`).
+                 ## 
+                 ## When `true` the pool will not create more than its
+                 ## configured capacity.  It a connection is requested, none
+                 ## are free, and the pool is at capacity, this will result
+                 ## in an Error being raised.
+  healthCheckQuery*: string  ## Should be a simple and fast SQL query that the
+                             ## pool can use to test the liveliness of pooled
+                             ## connections.
+  
+
+ + +  Source +  Edit + +
+
+ +
+
+

Procs

+
+
+
proc initDbConnPool(cfg: DbConnPoolConfig): DbConnPool {....raises: [Exception],
+    tags: [RootEffect].}
+
+ + +  Source +  Edit + +
+
+
+
proc release(pool: DbConnPool; connId: int): void {.
+    ...raises: [Exception, ValueError], tags: [RootEffect].}
+
+ +Release a connection back to the pool. +  Source +  Edit + +
+
+
+
proc take(pool: DbConnPool): tuple[id: int, conn: DbConn] {.
+    ...raises: [Exception, ValueError], tags: [RootEffect, ReadDbEffect, DbEffect].}
+
+ +

Request a connection from the pool. Returns a DbConn if the pool has free connections, or if it has the capacity to create a new connection. If the pool is configured with a hard capacity limit and is out of free connections, this will raise an Error.

+

Connections taken must be returned via release when the caller is finished using them in order for them to be released back to the pool.

+ +  Source +  Edit + +
+
+ +
+
+

Templates

+
+
+
template withConn(pool: DbConnPool; stmt: untyped): untyped
+
+ +

Convenience template to provide a connection from the pool for use in a statement block, automatically releasing that connnection when done.

+

The provided connection is injected as the variable conn in the statement body.

+ +  Source +  Edit + +
+
+ +
+ +
+
+ +
+ +
+
+
+ + + diff --git a/docs/fiber_orm/pool.idx b/docs/fiber_orm/pool.idx new file mode 100644 index 0000000..693accc --- /dev/null +++ b/docs/fiber_orm/pool.idx @@ -0,0 +1,6 @@ +DbConnPoolConfig fiber_orm/pool.html#DbConnPoolConfig pool: DbConnPoolConfig +DbConnPool fiber_orm/pool.html#DbConnPool pool: DbConnPool +initDbConnPool fiber_orm/pool.html#initDbConnPool,DbConnPoolConfig pool: initDbConnPool(cfg: DbConnPoolConfig): DbConnPool +take fiber_orm/pool.html#take,DbConnPool pool: take(pool: DbConnPool): tuple[id: int, conn: DbConn] +release fiber_orm/pool.html#release,DbConnPool,int pool: release(pool: DbConnPool; connId: int): void +withConn fiber_orm/pool.html#withConn.t,DbConnPool,untyped pool: withConn(pool: DbConnPool; stmt: untyped): untyped diff --git a/docs/fiber_orm/util.html b/docs/fiber_orm/util.html new file mode 100644 index 0000000..a88529f --- /dev/null +++ b/docs/fiber_orm/util.html @@ -0,0 +1,524 @@ + + + + + + + + + + + + + + + + + + +src/fiber_orm/util + + + + + + + + +
+
+

src/fiber_orm/util

+
+ +   Source +  Edit + +
+
+ +

Utility methods used internally by Fiber ORM.

+
+

Types

+
+
+
MutateClauses = object
+  columns*: seq[string]
+  placeholders*: seq[string]
+  values*: seq[string]
+
+
+ +Data structure to hold information about the clauses that should be added to a query. How these clauses are used will depend on the query. This common data structure provides the information needed to create WHERE clauses, UPDATE clauses, etc. +  Source +  Edit + +
+
+ +
+
+

Procs

+
+
+
proc createParseStmt(t, value: NimNode): NimNode {....raises: [], tags: [].}
+
+ +Utility method to create the Nim cod required to parse a value coming from the a database query. This is used by functions like rowToModel to parse the dataabase columns into the Nim object fields. +  Source +  Edit + +
+
+
+
proc dbFormat(dt: DateTime): string {....raises: [], tags: [].}
+
+ +Format a DateTime for inclusion in a SQL Query. +  Source +  Edit + +
+
+
+
proc dbFormat(s: string): string {....raises: [], tags: [].}
+
+ +Format a string for inclusion in a SQL Query. +  Source +  Edit + +
+
+
+
proc dbFormat[T](item: T): string
+
+ +For all other types, fall back on a defined $ function to create a string version of the value we can include in an SQL query> +  Source +  Edit + +
+
+
+
proc dbFormat[T](list: seq[T]): string
+
+ +Format a seq for inclusion in a SQL Query. +  Source +  Edit + +
+
+
+
proc dbNameToIdent(name: string): string {....raises: [], tags: [].}
+
+ +Map a DB name to a Nim identifier name. See the rules for name mapping +  Source +  Edit + +
+
+
+
proc identNameToDb(name: string): string {....raises: [], tags: [].}
+
+ +

Map a Nim identifier name to a DB name. See the rules for name mapping

+

TODO link above

+ +  Source +  Edit + +
+
+
+
proc parseDbArray(val: string): seq[string] {....raises: [ValueError], tags: [].}
+
+ +Parse a Postgres array column into a Nim seq[string] +  Source +  Edit + +
+
+
+
proc parsePGDatetime(val: string): DateTime {....raises: [KeyError, SyntaxError,
+    StudyError, ValueError, RegexInternalError, InvalidUnicodeError],
+    tags: [TimeEffect].}
+
+ +Parse a Postgres datetime value into a Nim DateTime object. +  Source +  Edit + +
+
+
+
proc pluralize(name: string): string {....raises: [], tags: [].}
+
+ +Return the plural form of the given name. +  Source +  Edit + +
+
+
+
proc tableName(modelType: type): string
+
+ +Get the table name for a given model class +  Source +  Edit + +
+
+
+
proc tableName[T](rec: T): string
+
+ +Get the table name for a given record. +  Source +  Edit + +
+
+
+
proc typeOfColumn(modelType: NimNode; colName: string): NimNode {.
+    ...raises: [Exception], tags: [].}
+
+ +Given a model type and a column name, return the Nim type for that column. +  Source +  Edit + +
+
+ +
+
+

Macros

+
+
+
macro columnNamesForModel(modelType: typed): seq[string]
+
+ +Return the column names corresponding to the the fields of the given model class +  Source +  Edit + +
+
+
+
macro listFields(t: typed): untyped
+
+ + +  Source +  Edit + +
+
+
+
macro modelName(model: object): string
+
+ +For a given concrete record object, return the name of the model class +  Source +  Edit + +
+
+
+
macro modelName(modelType: type): string
+
+ +Get the name of a given model class +  Source +  Edit + +
+
+
+
macro populateMutateClauses(t: typed; newRecord: bool; mc: var MutateClauses): untyped
+
+ +Given a record type, create the datastructure used to generate SQL clauses for the fields of this record type. +  Source +  Edit + +
+
+
+
macro rowToModel(modelType: typed; row: seq[string]): untyped
+
+ +Return a new Nim model object of type modelType populated with the values returned in the given database row +  Source +  Edit + +
+
+ +
+
+

Templates

+
+
+
template walkFieldDefs(t: NimNode; body: untyped)
+
+ +Iterate over every field of the given Nim object, yielding and defining fieldIdent and fieldType, the name of the field as a Nim Ident node and the type of the field as a Nim Type node respectively. +  Source +  Edit + +
+
+ +
+ +
+
+ +
+ +
+
+
+ + + diff --git a/docs/fiber_orm/util.idx b/docs/fiber_orm/util.idx new file mode 100644 index 0000000..e781aad --- /dev/null +++ b/docs/fiber_orm/util.idx @@ -0,0 +1,21 @@ +MutateClauses fiber_orm/util.html#MutateClauses util: MutateClauses +pluralize fiber_orm/util.html#pluralize,string util: pluralize(name: string): string +modelName fiber_orm/util.html#modelName.m util: modelName(model: object): string +modelName fiber_orm/util.html#modelName.m,type util: modelName(modelType: type): string +identNameToDb fiber_orm/util.html#identNameToDb,string util: identNameToDb(name: string): string +dbNameToIdent fiber_orm/util.html#dbNameToIdent,string util: dbNameToIdent(name: string): string +tableName fiber_orm/util.html#tableName,type util: tableName(modelType: type): string +tableName fiber_orm/util.html#tableName,T util: tableName[T](rec: T): string +dbFormat fiber_orm/util.html#dbFormat,string util: dbFormat(s: string): string +dbFormat fiber_orm/util.html#dbFormat,DateTime util: dbFormat(dt: DateTime): string +dbFormat fiber_orm/util.html#dbFormat,seq[T] util: dbFormat[T](list: seq[T]): string +dbFormat fiber_orm/util.html#dbFormat,T util: dbFormat[T](item: T): string +parsePGDatetime fiber_orm/util.html#parsePGDatetime,string util: parsePGDatetime(val: string): DateTime +parseDbArray fiber_orm/util.html#parseDbArray,string util: parseDbArray(val: string): seq[string] +createParseStmt fiber_orm/util.html#createParseStmt,NimNode,NimNode util: createParseStmt(t, value: NimNode): NimNode +walkFieldDefs fiber_orm/util.html#walkFieldDefs.t,NimNode,untyped util: walkFieldDefs(t: NimNode; body: untyped) +columnNamesForModel fiber_orm/util.html#columnNamesForModel.m,typed util: columnNamesForModel(modelType: typed): seq[string] +rowToModel fiber_orm/util.html#rowToModel.m,typed,seq[string] util: rowToModel(modelType: typed; row: seq[string]): untyped +listFields fiber_orm/util.html#listFields.m,typed util: listFields(t: typed): untyped +typeOfColumn fiber_orm/util.html#typeOfColumn,NimNode,string util: typeOfColumn(modelType: NimNode; colName: string): NimNode +populateMutateClauses fiber_orm/util.html#populateMutateClauses.m,typed,bool,MutateClauses util: populateMutateClauses(t: typed; newRecord: bool; mc: var MutateClauses): untyped diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..c727162 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,619 @@ + + + + + + + + + + + + + + + + + + +src/fiber_orm + + + + + + + + +
+
+

src/fiber_orm

+
+
+
+ +     Dark Mode +
+ +
+ Search: +
+
+ Group by: + +
+ + +
+   Source +  Edit + +
+
+ +

Lightweight ORM supporting the Postgres and SQLite databases in Nim. It supports a simple, opinionated model mapper to generate SQL queries based on Nim objects. It also includes a simple connection pooling implementation.

+

Fiber ORM is not intended to be a 100% all-cases-covered ORM that handles every potential data access pattern one might wish to implement. It is best thought of as a collection of common SQL generation patterns. It is intended to cover 90% of the common queries and functions one might write when implementing an SQL-based access layer. It is expected that there may be a few more complicated queries that need to be implemented to handle specific access patterns.

+

The simple mapping pattern provided by Fiber ORM also works well on top of databases that encapsulate data access logic in SQL with, for example, views.

+ +

Basic Usage

Consider a simple TODO list application that keeps track of TODO items as well as time logged against those items.

+ +

Example DB Schema

You might have a schema such as:

+
create extension if not exists "pgcrypto";
+
+create table todo_items columns (
+  id uuid not null primary key default gen_random_uuid(),
+  owner varchar not null,
+  summary varchar not null,
+  details varchar default null,
+  priority integer not null default 0,
+  related_todo_item_ids uuid[] not null default '{}'
+);
+
+create table time_entries columns (
+  id uuid not null primary key default gen_random_uuid(),
+  todo_item_id uuid not null references todo_items (id) on delete cascade,
+  start timestamp with timezone not null default current_timestamp,
+  stop timestamp with timezone default null,
+);
+

Example Model Definitions

Models may be defined as:

+
# models.nim
+import std/options, std/times
+import uuids
+
+type
+  TodoItem* = object
+    id*: UUID
+    owner*: string
+    summary*: string
+    details*: Option[string]
+    priority*: int
+    relatedTodoItemIds*: seq[UUID]
+  
+  TimeEntry* = object
+    id*: UUID
+    todoItemId*: Option[UUID]
+    start*: DateTime
+    stop*: Option[DateTime]
+

Example Fiber ORM Usage

Using Fiber ORM we can generate a data access layer with:

+
# db.nim
+import fiber_orm
+import ./models.nim
+
+type TodoDB* = DbConnPool
+
+proc initDb*(connString: string): TodoDB =
+  result = fiber_orm.initPool(
+    connect = proc(): DbConn = open("", "", "", connString),
+    poolSize = 20,
+    hardCap = false)
+
+
+generateProcsForModels(TodoDB, [TodoItem, TimeEntry])
+
+generateLookup(TodoDB, TimeEntry, @["todoItemId"])

This will generate the following procedures:

+
proc getTodoItem*(db: TodoDB, id: UUID): TodoItem;
+proc getAllTodoItems*(db: TodoDB): seq[TodoItem];
+proc createTodoItem*(db: TodoDB, rec: TodoItem): TodoItem;
+proc updateTodoItem*(db: TodoDB, rec: TodoItem): bool;
+proc deleteTodoItem*(db: TodoDB, rec: TodoItem): bool;
+proc deleteTodoItem*(db: TodoDB, id: UUID): bool;
+
+proc findTodoItemsWhere*(db: TodoDB, whereClause: string,
+  values: varargs[string, dbFormat]): seq[TodoItem];
+
+proc getTimeEntry*(db: TodoDB, id: UUID): TimeEntry;
+proc getAllTimeEntries*(db: TodoDB): seq[TimeEntry];
+proc createTimeEntry*(db: TodoDB, rec: TimeEntry): TimeEntry;
+proc updateTimeEntry*(db: TodoDB, rec: TimeEntry): bool;
+proc deleteTimeEntry*(db: TodoDB, rec: TimeEntry): bool;
+proc deleteTimeEntry*(db: TodoDB, id: UUID): bool;
+
+proc findTimeEntriesWhere*(db: TodoDB, whereClause: string,
+  values: varargs[string, dbFormat]): seq[TimeEntry];
+
+proc findTimeEntriesByTodoItemId(db: TodoDB, todoItemId: UUID): seq[TimeEntry];
+

Object-Relational Modeling

+

Model Class

Fiber ORM uses simple Nim objects and ref objects as model classes. Fiber ORM expects there to be one table for each model class.

+ +

Name Mapping

Fiber ORM uses snake_case for database identifiers (column names, table names, etc.) and camelCase for Nim identifiers. We automatically convert model names to and from table names (TodoItem <-> todo_items), as well as column names (userId <-> user_id).

+

Notice that table names are automatically pluralized from model class names. In the above example, you have:

+ + + +
Model ClassTable Name
TodoItemtodo_items
TimeEntrytime_entries

Because Nim is style-insensitive, you can generall refer to model classes and fields using snake_case, camelCase, or PascalCase in your code and expect Fiber ORM to be able to map the names to DB identifier names properly (though FiberORM will always use camelCase internally).

+

See the identNameToDb, dbNameToIdent, tableName and dbFormat procedures in the fiber module for details.

+ +

ID Field

Fiber ORM expects every model class to have a field named id, with a corresponding id column in the model table. This field must be either a string, integer, or UUID.

+

When creating a new record the id field will be omitted if it is empty (Option.isNone, UUID.isZero, value of 0, or only whitespace). This is intended to allow for cases like the example where the database may generate an ID when a new record is inserted. If a non-zero value is provided, the create call will include the id field in the INSERT query.

+

For example, to allow the database to create the id:

+
let item = TodoItem(
+  owner: "John Mann",
+  summary: "Create a grocery list.",
+  details: none[string](),
+  priority: 0,
+  relatedTodoItemIds: @[])
+
+let itemWithId = db.createTodoItem(item)
+echo $itemWithId.id # generated in the database

And to create it in code:

+
import uuids
+
+let item = TodoItem(
+  id: genUUID(),
+  owner: "John Mann",
+  summary: "Create a grocery list.",
+  details: none[string](),
+  priority: 0,
+  relatedTodoItemIds: @[])
+
+let itemInDb = db.createTodoItem(item)
+echo $itemInDb.id # will be the same as what was provided
+

Supported Data Types

The following Nim data types are supported by Fiber ORM:

+ + + + + + + + + + +
Nim TypePostgres TypeSQLite Type
stringvarchar
intinteger
floatdouble
boolboolean
DateTimetimestamp
seq[]array
UUIDuuid (pg)
Optionallows NULL [1]
JsonNodejsonb

+
  Note that this implies that all NULL-able fields should be typed as optional using Option[fieldType]. Conversely, any fields with non-optional types should also be constrained to be NOT NULL in the database schema. +
+
+ +

Database Object

Many of the Fiber ORM macros expect a database object type to be passed. In the example above the pool.DbConnPool object is used as database object type (aliased as TodoDB). This is the intended usage pattern, but anything can be passed as the database object type so long as there is a defined withConn template that provides an injected conn: DbConn object to the provided statement body.

+

For example, a valid database object implementation that opens a new connection for every request might look like this:

+
import std/db_postgres
+
+type TodoDB* = object
+  connString: string
+
+template withConn*(db: TodoDB, stmt: untyped): untyped =
+  let conn {.inject.} = open("", "", "", db.connString)
+  try: stmt
+  finally: close(conn)
+

See Also

fiber_orm/pool

+

+ +
+

Types

+
+
+
NotFoundError = object of CatchableError
+
+ + + Error type raised when no record matches a given ID +  Source +  Edit + +
+
+ +
+
+

Procs

+
+
+
proc createRecord[T](db: DbConn; rec: T): T
+
+ +

Create a new record. rec is expected to be a model class. The id field is only set if it is non-empty (see ID Field for details).

+

Returns the newly created record.

+ +  Source +  Edit + +
+
+
+
proc deleteRecord[T](db: DbConn; rec: T): bool
+
+ +Delete a record by id. +  Source +  Edit + +
+
+
+
proc initPool(connect: proc (): DbConn; poolSize = 10; hardCap = false;
+              healthCheckQuery = "SELECT \'true\' AS alive"): DbConnPool {.
+    ...raises: [Exception], tags: [RootEffect].}
+
+ +Initialize a new DbConnPool. See the initDb procedure in the Example Fiber ORM Usage for an example
  • connect must be a factory which creates a new DbConn.
  • +
  • poolSize sets the desired capacity of the connection pool.
  • +
  • hardCap defaults to false. When false, the pool can grow beyond the configured capacity, but will release connections down to the its capacity (no less than poolSize).

    +

    When true the pool will not create more than its configured capacity. It a connection is requested, none are free, and the pool is at capacity, this will result in an Error being raised.

    +
  • +
  • healthCheckQuery should be a simple and fast SQL query that the pool can use to test the liveliness of pooled connections.
  • +
+ +  Source +  Edit + +
+
+
+
proc updateRecord[T](db: DbConn; rec: T): bool
+
+ +Update a record by id. rec is expected to be a model class. +  Source +  Edit + +
+
+ +
+
+

Macros

+
+
+
macro generateLookup(dbType: type; modelType: type; fields: seq[string]): untyped
+
+ +Create a lookup procedure for a given set of field names. For example, given the TODO database demostrated above,
generateLookup(TodoDB, TodoItem, ["owner", "priority"])

will generate the following procedure:

+
proc findTodoItemsByOwnerAndPriority*(db: SampleDB,
+  owner: string, priority: int): seq[TodoItem]
+  Source +  Edit + +
+
+
+
macro generateProcsForFieldLookups(dbType: type; modelsAndFields: openArray[
+    tuple[t: type, fields: seq[string]]]): untyped
+
+ + +  Source +  Edit + +
+
+
+
macro generateProcsForModels(dbType: type; modelTypes: openArray[type]): untyped
+
+ +Generate all standard access procedures for the given model types. For a model class named TodoItem, this will generate the following procedures:
proc getTodoItem*(db: TodoDB, id: idType): TodoItem;
+proc getAllTodoItems*(db: TodoDB): TodoItem;
+proc createTodoItem*(db: TodoDB, rec: TodoItem): TodoItem;
+proc deleteTodoItem*(db: TodoDB, rec: TodoItem): bool;
+proc deleteTodoItem*(db: TodoDB, id: idType): bool;
+proc updateTodoItem*(db: TodoDB, rec: TodoItem): bool;
+
+proc findTodoItemsWhere*(
+  db: TodoDB, whereClause: string, values: varargs[string]): TodoItem;

dbType is expected to be some type that has a defined withConn procedure (see Database Object for details).

+ +  Source +  Edit + +
+
+ +
+
+

Templates

+
+
+
template deleteRecord(db: DbConn; modelType: type; id: typed): untyped
+
+ +Delete a record by id. +  Source +  Edit + +
+
+
+
template findRecordsBy(db: DbConn; modelType: type;
+                       lookups: seq[tuple[field: string, value: string]]): untyped
+
+ +Find all records matching the provided lookup values. +  Source +  Edit + +
+
+
+
template findRecordsWhere(db: DbConn; modelType: type; whereClause: string;
+                          values: varargs[string, dbFormat]): untyped
+
+ +Find all records matching a given WHERE clause. The number of elements in the values array must match the number of placeholders (?) in the provided WHERE clause. +  Source +  Edit + +
+
+
+
template getAllRecords(db: DbConn; modelType: type): untyped
+
+ +Fetch all records of the given type. +  Source +  Edit + +
+
+
+
template getRecord(db: DbConn; modelType: type; id: typed): untyped
+
+ +Fetch a record by id. +  Source +  Edit + +
+
+
+
template inTransaction(db: DbConnPool; body: untyped)
+
+ + +  Source +  Edit + +
+
+ +
+ + +
+
+ +
+ +
+
+
+ + + diff --git a/docs/nimdoc.out.css b/docs/nimdoc.out.css new file mode 100644 index 0000000..4abea9c --- /dev/null +++ b/docs/nimdoc.out.css @@ -0,0 +1,1016 @@ +/* +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 and narimiran +*/ + +:root { + --primary-background: #fff; + --secondary-background: ghostwhite; + --third-background: #e8e8e8; + --info-background: #50c050; + --warning-background: #c0a000; + --error-background: #e04040; + --border: #dde; + --text: #222; + --anchor: #07b; + --anchor-focus: #607c9f; + --input-focus: #1fa0eb; + --strong: #3c3c3c; + --hint: #9A9A9A; + --nim-sprite-base64: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAN4AAAA9CAYAAADCt9ebAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFFmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDggNzkuMTY0MDM2LCAyMDE5LzA4LzEzLTAxOjA2OjU3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDE5LTEyLTAzVDAxOjAzOjQ4KzAxOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0xMi0wM1QwMjoyODo0MSswMTowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOS0xMi0wM1QwMjoyODo0MSswMTowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDozMzM0ZjAxYS0yMDExLWE1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"); + + --keyword: #5e8f60; + --identifier: #222; + --comment: #484a86; + --operator: #155da4; + --punctuation: black; + --other: black; + --escapeSequence: #c4891b; + --number: #252dbe; + --literal: #a4255b; + --program: #6060c0; + --option: #508000; + --raw-data: #a4255b; +} + +[data-theme="dark"] { + --primary-background: #171921; + --secondary-background: #1e202a; + --third-background: #2b2e3b; + --info-background: #008000; + --warning-background: #807000; + --error-background: #c03000; + --border: #0e1014; + --text: #fff; + --anchor: #8be9fd; + --anchor-focus: #8be9fd; + --input-focus: #8be9fd; + --strong: #bd93f9; + --hint: #7A7C85; + --nim-sprite-base64: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARMAAABMCAYAAABOBlMuAAAACXBIWXMAAAsTAAALEwEAmpwYAAAFFmlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDggNzkuMTY0MDM2LCAyMDE5LzA4LzEzLTAxOjA2OjU3ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgMjEuMCAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDE5LTEyLTAzVDAxOjE4OjIyKzAxOjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOS0xMi0wM1QwMToyMDoxMCswMTowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOS0xMi0wM1QwMToyMDoxMCswMTowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDplZGViMzU3MC1iNmZjLWQy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"); + + --keyword: #ff79c6; + --identifier: #f8f8f2; + --comment: #6272a4; + --operator: #ff79c6; + --punctuation: #f8f8f2; + --other: #f8f8f2; + --escapeSequence: #bd93f9; + --number: #bd93f9; + --literal: #f1fa8c; + --program: #9090c0; + --option: #90b010; + --raw-data: #8be9fd; +} + +.theme-switch-wrapper { + display: flex; + align-items: center; +} + +.theme-switch-wrapper em { + margin-left: 10px; + font-size: 1rem; +} + +.theme-switch { + display: inline-block; + height: 22px; + position: relative; + width: 50px; +} + +.theme-switch input { + display: none; +} + +.slider { + background-color: #ccc; + bottom: 0; + cursor: pointer; + left: 0; + position: absolute; + right: 0; + top: 0; + transition: .4s; +} + +.slider:before { + background-color: #fff; + bottom: 4px; + content: ""; + height: 13px; + left: 4px; + position: absolute; + transition: .4s; + width: 13px; +} + +input:checked + .slider { + background-color: #66bb6a; +} + +input:checked + .slider:before { + transform: translateX(26px); +} + +.slider.round { + border-radius: 17px; +} + +.slider.round:before { + border-radius: 50%; +} + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; } + +body { + font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; + font-weight: 400; + font-size: 1.125em; + line-height: 1.5; + color: var(--text); + background-color: var(--primary-background); } + +/* Skeleton grid */ +.container { + position: relative; + width: 100%; + max-width: 1050px; + margin: 0 auto; + padding: 0; + box-sizing: border-box; } + +.column, +.columns { + width: 100%; + float: left; + box-sizing: border-box; + margin-left: 1%; +} + +.column:first-child, +.columns:first-child { + margin-left: 0; } + +.three.columns { + width: 22%; +} + +.nine.columns { + width: 77.0%; } + +.twelve.columns { + width: 100%; + margin-left: 0; } + +@media screen and (max-width: 860px) { + .three.columns { + display: none; + } + .nine.columns { + width: 98.0%; + } + body { + font-size: 1em; + line-height: 1.35; + } +} + +cite { + font-style: italic !important; } + + +/* Nim search input */ +div#searchInputDiv { + margin-bottom: 1em; +} +input#searchInput { + width: 80%; +} + +/* + * Some custom formatting for input forms. + * This also fixes input form colors on Firefox with a dark system theme on Linux. + */ +input { + -moz-appearance: none; + background-color: var(--secondary-background); + color: var(--text); + border: 1px solid var(--border); + font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; + font-size: 0.9em; + padding: 6px; +} + +input:focus { + border: 1px solid var(--input-focus); + box-shadow: 0 0 3px var(--input-focus); +} + +select { + -moz-appearance: none; + background-color: var(--secondary-background); + color: var(--text); + border: 1px solid var(--border); + font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif; + font-size: 0.9em; + padding: 6px; +} + +select:focus { + border: 1px solid var(--input-focus); + box-shadow: 0 0 3px var(--input-focus); +} + +/* Docgen styles */ + +:target { + border: 2px solid #B5651D; + border-style: dotted; +} + +/* Links */ +a { + color: var(--anchor); + text-decoration: none; +} + +a span.Identifier { + text-decoration: underline; + text-decoration-color: #aab; +} + +a.reference-toplevel { + font-weight: bold; +} + +a.toc-backref { + text-decoration: none; + color: var(--text); } + +a.link-seesrc { + color: #607c9f; + font-size: 0.9em; + font-style: italic; } + +a:hover, +a:focus { + color: var(--anchor-focus); + text-decoration: underline; } + +a:hover span.Identifier { + color: var(--anchor); +} + + +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; } +} + + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +small { + font-size: 85%; } + +strong { + font-weight: 600; + font-size: 0.95em; + color: var(--strong); +} + +em { + font-style: italic; } + +h1 { + font-size: 1.8em; + font-weight: 400; + padding-bottom: .25em; + border-bottom: 6px solid var(--third-background); + margin-top: 2.5em; + margin-bottom: 1em; + line-height: 1.2em; } + +h1.title { + padding-bottom: 1em; + border-bottom: 0px; + font-size: 2.5em; + text-align: center; + font-weight: 900; + margin-top: 0.75em; + margin-bottom: 0em; +} + +h2 { + font-size: 1.3em; + margin-top: 2em; } + +h2.subtitle { + margin-top: 0em; + text-align: center; } + +h3 { + font-size: 1.125em; + font-style: italic; + margin-top: 1.5em; } + +h4 { + font-size: 1.125em; + margin-top: 1em; } + +h5 { + font-size: 1.125em; + margin-top: 0.75em; } + +h6 { + font-size: 1.1em; } + + +ul, +ol { + padding: 0; + margin-top: 0.5em; + margin-left: 0.75em; } + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; + margin-left: 1.25em; } + +ul.simple > li { + list-style-type: circle; +} + +ul.simple-boot li { + list-style-type: none; + margin-left: 0em; + margin-bottom: 0.5em; +} + +ol.simple > li, ul.simple > li { + margin-bottom: 0.2em; + margin-left: 0.4em } + +ul.simple.simple-toc > li { + margin-top: 1em; +} + +ul.simple-toc { + list-style: none; + font-size: 0.9em; + margin-left: -0.3em; + margin-top: 1em; } + +ul.simple-toc > li { + list-style-type: none; +} + +ul.simple-toc-section { + list-style-type: circle; + margin-left: 0.8em; + color: #6c9aae; } + +ul.nested-toc-section { + list-style-type: circle; + margin-left: -0.75em; + color: var(--text); +} + +ul.nested-toc-section > li { + margin-left: 1.25em; +} + + +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; } + +ul.auto-toc { + list-style-type: none; } + + +dl { + margin-bottom: 1.5em; } + +dt { + margin-bottom: -0.5em; + margin-left: 0.0em; } + +dd { + margin-left: 2.0em; + margin-bottom: 3.0em; + margin-top: 0.5em; } + + +hr { + margin: 2em 0; + border: 0; + border-top: 1px solid #aaa; } + +hr.footnote { + width: 25%; + border-top: 0.15em solid #999; + margin-bottom: 0.15em; + margin-top: 0.15em; +} +div.footnote-group { + margin-left: 1em; } +div.footnote-label { + display: inline-block; + min-width: 1.7em; +} + +div.option-list { + border: 0.1em solid var(--border); +} +div.option-list-item { + padding-left: 12em; + padding-right: 0; + padding-bottom: 0.3em; + padding-top: 0.3em; +} +div.odd { + background-color: var(--secondary-background); +} +div.option-list-label { + margin-left: -11.5em; + margin-right: 0em; + min-width: 11.5em; + display: inline-block; + vertical-align: top; +} +div.option-list-description { + width: calc(100% - 1em); + padding-left: 1em; + padding-right: 0; + display: inline-block; +} + +blockquote { + font-size: 0.9em; + font-style: italic; + padding-left: 0.5em; + margin-left: 0; + border-left: 5px solid #bbc; +} + +.pre, span.tok { + font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; + font-weight: 500; + font-size: 0.85em; + color: var(--text); + background-color: var(--third-background); + padding-left: 3px; + padding-right: 3px; + border-radius: 4px; +} + +span.tok { + border: 1px solid #808080; + padding-bottom: 0.1em; + margin-right: 0.2em; +} + +pre { + font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; + color: var(--text); + font-weight: 500; + display: inline-block; + box-sizing: border-box; + min-width: 100%; + padding: 0.5em; + margin-top: 0.5em; + margin-bottom: 0.5em; + font-size: 0.85em; + white-space: pre !important; + overflow-y: hidden; + overflow-x: visible; + background-color: var(--secondary-background); + border: 1px solid var(--border); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; } + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; } + + +/* 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: ghostwhite; + 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%); + filter: opacity(75%); + text-align: right; + border-color: transparent; + background-color: transparent; + padding-left: 0px; + margin-left: 0px; + padding-right: 0px; + margin-right: 0px; } + + +table { + max-width: 100%; + background-color: transparent; + margin-top: 0.5em; + margin-bottom: 1.5em; + border-collapse: collapse; + border-color: var(--third-background); + border-spacing: 0; + font-size: 0.9em; +} + +table th, table td { + padding: 0px 0.5em 0px; + border-color: var(--third-background); +} + +table th { + background-color: var(--third-background); + border-color: var(--third-background); + font-weight: bold; } + +table th.docinfo-name { + background-color: transparent; + text-align: right; +} + +table tr:hover { + background-color: var(--third-background); } + + +/* 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; } + +.admonition { + padding: 0.3em; + background-color: var(--secondary-background); + border-left: 0.4em solid #7f7f84; + margin-bottom: 0.5em; + -webkit-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); + -moz-box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); + box-shadow: 0 5px 8px -6px rgba(0,0,0,.2); +} +.admonition-info { + border-color: var(--info-background); +} +.admonition-info-text { + color: var(--info-background); +} +.admonition-warning { + border-color: var(--warning-background); +} +.admonition-warning-text { + color: var(--warning-background); +} +.admonition-error { + border-color: var(--error-background); +} +.admonition-error-text { + color: var(--error-background); +} + +.first { + /* Override more specific margin styles with "! important". */ + margin-top: 0 !important; } + +.last, .with-subtitle { + margin-bottom: 0 !important; } + +.hidden { + display: none; } + +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; } + + +div.figure { + margin-left: 2em; + margin-right: 2em; } + +div.footer, div.header { + clear: both; + text-align: center; + color: #666; + font-size: smaller; } + +div.footer { + padding-top: 5em; +} + +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.topic { + margin: 2em; } + +div.search_results { + background-color: var(--third-background); + margin: 3em; + padding: 1em; + border: 1px solid #4d4d4d; +} + +div#global-links ul { + margin-left: 0; + list-style-type: none; +} + +div#global-links > simple-boot { + margin-left: 3em; +} + +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; } + +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.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-style: oblique; } + +span.classifier-delimiter { + font-weight: bold; } + +span.problematic { + color: #b30000; } + +span.section-subtitle { + /* font-size relative to parent (h1..h6 element) */ + font-size: 80%; } + +span.DecNumber { + color: var(--number); } + +span.BinNumber { + color: var(--number); } + +span.HexNumber { + color: var(--number); } + +span.OctNumber { + color: var(--number); } + +span.FloatNumber { + color: var(--number); } + +span.Identifier { + color: var(--identifier); } + +span.Keyword { + font-weight: 600; + color: var(--keyword); } + +span.StringLit { + color: var(--literal); } + +span.LongStringLit { + color: var(--literal); } + +span.CharLit { + color: var(--literal); } + +span.EscapeSequence { + color: var(--escapeSequence); } + +span.Operator { + color: var(--operator); } + +span.Punctuation { + color: var(--punctuation); } + +span.Comment, span.LongComment { + font-style: italic; + font-weight: 400; + color: var(--comment); } + +span.RegularExpression { + color: darkviolet; } + +span.TagStart { + color: darkviolet; } + +span.TagEnd { + color: darkviolet; } + +span.Key { + color: #252dbe; } + +span.Value { + color: #252dbe; } + +span.RawData { + color: var(--raw-data); } + +span.Assembler { + color: #252dbe; } + +span.Preprocessor { + color: #252dbe; } + +span.Directive { + color: #252dbe; } + +span.option { + font-weight: bold; + font-family: "Source Code Pro", Monaco, Menlo, Consolas, "Courier New", monospace; + color: var(--option); +} + +span.Prompt { + font-weight: bold; + color: red; } + +span.ProgramOutput { + font-weight: bold; + color: #808080; } + +span.program { + font-weight: bold; + color: var(--program); + text-decoration: underline; + text-decoration-color: var(--hint); + text-decoration-thickness: 0.05em; + text-underline-offset: 0.15em; +} + +span.Command, span.Rule, span.Hyperlink, span.Label, span.Reference, +span.Other { + color: var(--other); } + +/* Pop type, const, proc, and iterator defs in nim def blocks */ +dt pre > span.Identifier, dt pre > span.Operator { + color: var(--identifier); + font-weight: 700; } + +dt pre > span.Keyword ~ span.Identifier, dt pre > span.Identifier ~ span.Identifier, +dt pre > span.Operator ~ span.Identifier, dt pre > span.Other ~ span.Identifier { + color: var(--identifier); + font-weight: inherit; } + +/* Nim sprite for the footer (taken from main page favicon) */ +.nim-sprite { + display: inline-block; + width: 51px; + height: 14px; + background-position: 0 0; + background-size: 51px 14px; + -webkit-filter: opacity(50%); + filter: opacity(50%); + background-repeat: no-repeat; + background-image: var(--nim-sprite-base64); + margin-bottom: 5px; } + +span.pragmadots { + /* Position: relative frees us up to make the dots + look really nice without fucking up the layout and + causing bulging in the parent container */ + position: relative; + /* 1px down looks slightly nicer */ + top: 1px; + padding: 2px; + background-color: var(--third-background); + border-radius: 4px; + margin: 0 2px; + cursor: pointer; + font-size: 0.8em; +} + +span.pragmadots:hover { + background-color: var(--hint); +} +span.pragmawrap { + display: none; +} + +span.attachedType { + display: none; + visibility: hidden; +} diff --git a/docs/theindex.html b/docs/theindex.html new file mode 100644 index 0000000..8e842b9 --- /dev/null +++ b/docs/theindex.html @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + +Index + + + + + + + + +
+
+

Index

+ Modules: fiber_orm, fiber_orm/pool, fiber_orm/util.

API symbols

+
columnNamesForModel:
+
createParseStmt:
+
createRecord:
+
DbConnPool:
+
DbConnPoolConfig:
+
dbFormat:
+
dbNameToIdent:
+
deleteRecord:
+
findRecordsBy:
+
findRecordsWhere:
+
generateLookup:
+
generateProcsForFieldLookups:
+
generateProcsForModels:
+
getAllRecords:
+
getRecord:
+
identNameToDb:
+
initDbConnPool:
+
initPool:
+
inTransaction:
+
listFields:
+
modelName:
+
MutateClauses:
+
NotFoundError:
+
parseDbArray:
+
parsePGDatetime:
+
pluralize:
+
populateMutateClauses:
+
release:
+
rowToModel:
+
tableName:
+
take:
+
typeOfColumn:
+
updateRecord:
+
walkFieldDefs:
+
withConn:
+
+
+ +
+
+
+ + + diff --git a/src/fiber_orm.nim b/src/fiber_orm.nim index 1327a49..5f852c6 100644 --- a/src/fiber_orm.nim +++ b/src/fiber_orm.nim @@ -25,7 +25,12 @@ ## =========== ## ## Consider a simple TODO list application that keeps track of TODO items as -## well as time logged against those items. You might have a schema such as: +## well as time logged against those items. +## +## Example DB Schema +## ----------------- +## +## You might have a schema such as: ## ## .. code-block:: SQL ## create extension if not exists "pgcrypto"; @@ -46,6 +51,9 @@ ## stop timestamp with timezone default null, ## ); ## +## Example Model Definitions +## ------------------------- +## ## Models may be defined as: ## ## .. code-block:: Nim @@ -68,6 +76,9 @@ ## start*: DateTime ## stop*: Option[DateTime] ## +## Example Fiber ORM Usage +## ----------------------- +## ## Using Fiber ORM we can generate a data access layer with: ## ## .. code-block:: Nim @@ -78,8 +89,11 @@ ## type TodoDB* = DbConnPool ## ## proc initDb*(connString: string): TodoDB = -## fiber_orm.initPool(connect = -## proc(): DbConn = open("", "", "", connString)) +## result = fiber_orm.initPool( +## connect = proc(): DbConn = open("", "", "", connString), +## poolSize = 20, +## hardCap = false) +## ## ## generateProcsForModels(TodoDB, [TodoItem, TimeEntry]) ## @@ -163,6 +177,35 @@ ## generate an ID when a new record is inserted. If a non-zero value is ## provided, the create call will include the `id` field in the `INSERT` query. ## +## For example, to allow the database to create the id: +## +## .. code-block:: Nim +## let item = TodoItem( +## owner: "John Mann", +## summary: "Create a grocery list.", +## details: none[string](), +## priority: 0, +## relatedTodoItemIds: @[]) +## +## let itemWithId = db.createTodoItem(item) +## echo $itemWithId.id # generated in the database +## +## And to create it in code: +## +## .. code-block:: Nim +## import uuids +## +## let item = TodoItem( +## id: genUUID(), +## owner: "John Mann", +## summary: "Create a grocery list.", +## details: none[string](), +## priority: 0, +## relatedTodoItemIds: @[]) +## +## let itemInDb = db.createTodoItem(item) +## echo $itemInDb.id # will be the same as what was provided +## ## .. _Option.isNone: https://nim-lang.org/docs/options.html#isNone,Option[T] ## .. _UUID.isZero: https://github.com/pragmagic/uuids/blob/8cb8720b567c6bcb261bd1c0f7491bdb5209ad06/uuids.nim#L72 ## @@ -206,7 +249,30 @@ ## ## Database Object ## =============== - +## +## Many of the Fiber ORM macros expect a database object type to be passed. +## In the example above the `pool.DbConnPool`_ object is used as database +## object type (aliased as `TodoDB`). This is the intended usage pattern, but +## anything can be passed as the database object type so long as there is a +## defined `withConn` template that provides an injected `conn: DbConn` object +## to the provided statement body. +## +## For example, a valid database object implementation that opens a new +## connection for every request might look like this: +## +## .. code-block:: Nim +## import std/db_postgres +## +## type TodoDB* = object +## connString: string +## +## template withConn*(db: TodoDB, stmt: untyped): untyped = +## let conn {.inject.} = open("", "", "", db.connString) +## try: stmt +## finally: close(conn) +## +## .. _pool.DbConnPool: fiber_orm/pool.html#DbConnPool +## import std/db_postgres, std/macros, std/options, std/sequtils, std/strutils import namespaced_logging, uuids @@ -241,14 +307,13 @@ proc newMutateClauses(): MutateClauses = values: @[]) proc createRecord*[T](db: DbConn, rec: T): T = - ## Create a new record. `rec` is expected to be a `model class`_. The `id - ## field`_ is only set if it is `non-empty`_ + ## Create a new record. `rec` is expected to be a `model class`_. The `id` + ## field is only set if it is non-empty (see `ID Field`_ for details). ## ## Returns the newly created record. ## ## .. _model class: #objectminusrelational-modeling-model-class - ## .. _id field: #model-class-id-field - ## .. _non-empty: + ## .. _ID Field: #model-class-id-field var mc = newMutateClauses() populateMutateClauses(rec, true, mc) @@ -266,8 +331,6 @@ proc createRecord*[T](db: DbConn, rec: T): T = proc updateRecord*[T](db: DbConn, rec: T): bool = ## Update a record by id. `rec` is expected to be a `model class`_. - ## - ## .. _model class: #objectminusrelational-modeling-model-class var mc = newMutateClauses() populateMutateClauses(rec, false, mc) @@ -359,8 +422,10 @@ macro generateProcsForModels*(dbType: type, modelTypes: openarray[type]): untype ## proc findTodoItemsWhere*( ## db: TodoDB, whereClause: string, values: varargs[string]): TodoItem; ## - ## `dbType` is expected to be some type that has a defined `withConn`_ - ## procedure. + ## `dbType` is expected to be some type that has a defined `withConn` + ## procedure (see `Database Object`_ for details). + ## + ## .. _Database Object: #database-object result = newStmtList() for t in modelTypes: @@ -471,12 +536,12 @@ proc initPool*( poolSize = 10, hardCap = false, healthCheckQuery = "SELECT 'true' AS alive"): DbConnPool = - ## Initialize a new DbConnPool. + ## Initialize a new DbConnPool. See the `initDb` procedure in the `Example + ## Fiber ORM Usage`_ for an example ## - ## * `connect` must be a factory which creates a new `DbConn` + ## * `connect` must be a factory which creates a new `DbConn`. ## * `poolSize` sets the desired capacity of the connection pool. ## * `hardCap` defaults to `false`. - ## ## When `false`, the pool can grow beyond the configured capacity, but will ## release connections down to the its capacity (no less than `poolSize`). ## @@ -485,6 +550,8 @@ proc initPool*( ## capacity, this will result in an Error being raised. ## * `healthCheckQuery` should be a simple and fast SQL query that the pool ## can use to test the liveliness of pooled connections. + ## + ## .. _Example Fiber ORM Usage: #basic-usage-example-fiber-orm-usage initDbConnPool(DbConnPoolConfig( connect: connect,