1 namespace ort {
    2 	/**
    3 	 * Facilities to manipulate 64-bit numbers encoded as strings.
    4 	 * The JavaScript implementation of openradtool uses strings for numbers
    5 	 * because of the 64-bit problem: internally, openradtool uses 64-bit
    6 	 * integer numbers, but JavaScript has only 53 bits of precision for
    7 	 * integers, and 32 for bit-wise operations.
    8 	 * This class is a modified version of long.js fixed to base 10 and
    9 	 * converted to TypeScript.
   10 	 *
   11 	 * Original source: https://github.com/dcodeIO/long.js
   12 	 *
   13 	 * @license
   14 	 * Copyright 2009 The Closure Library Authors.
   15 	 * Copyright 2020 Daniel Wirtz / The long.js Contributors.
   16 	 * Copyright 2021 Kristaps Dzonsons
   17 	 * SPDX-License-Identifier: Apache-2.0
   18 	 */
   19 	export class Long {
   20 		private readonly __isLong__: boolean = true;
   21 		private readonly low: number;
   22 		private readonly high: number;
   23 		private readonly unsigned: boolean;
   24 
   25 		private constructor(low: number,
   26 			high?: number, unsigned?: boolean)
   27 		{
   28 			this.low = low | 0;
   29 			this.high = 
   30 				(typeof high === 'undefined') ?
   31 				0 : (high | 0);
   32 			this.unsigned = 
   33 				(typeof unsigned === 'undefined') ?
   34 				false: unsigned;
   35 		}
   36 
   37 		static readonly ZERO: Long = new Long(0, 0);
   38 		static readonly ONE: Long = new Long(1, 0);
   39 		static readonly UZERO: Long = new Long(0, 0, true);
   40 		static readonly TEN_TO_EIGHT: Long = new Long(100000000, 0);
   41 
   42 		static readonly MIN_VALUE: Long = 
   43 			new Long(0, 0x80000000|0, false);
   44 		static readonly MAX_UNSIGNED_VALUE: Long = 
   45 			new Long(0xFFFFFFFF|0, 0xFFFFFFFF|0, true);
   46 		static readonly  MAX_VALUE: Long = 
   47 			new Long(0xFFFFFFFF|0, 0x7FFFFFFF|0, false);
   48 
   49 		/* Constant numbers used in the code. */
   50 
   51 		private static readonly TWO_PWR_16_DBL: number = 
   52 			(1 << 16);
   53 		private static readonly TWO_PWR_32_DBL: number = 
   54 			Long.TWO_PWR_16_DBL *
   55 			Long.TWO_PWR_16_DBL;
   56 		private static readonly TWO_PWR_64_DBL: number =
   57 			Long.TWO_PWR_32_DBL *
   58 			Long.TWO_PWR_32_DBL;
   59 		private static readonly TWO_PWR_63_DBL: number = 
   60 			Long.TWO_PWR_64_DBL / 2;
   61 
   62 		/**
   63 		 * @return Whether this is a ortns.Long object.
   64 		 */
   65 		static isLong(obj: any): boolean 
   66 		{
   67 			/* 
   68 			 * Complex to silence a typescript warning about
   69 			 * __isLong__ being an unused local otherwise.
   70 			 */
   71 
   72 			return typeof obj === 'object' &&
   73 		 	       obj !== null && 
   74 			       '__isLong__' in obj &&
   75 			       (<Long>obj).__isLong__ === true;
   76 		}
   77 
   78 		/**
   79 		 * Convert to a JavaScript number, losing precision
   80 		 * (from 64 to 53 bits) and thus possibly truncating
   81 		 * with larger or smaller numbers.
   82 		 * @return The Long converted to a number.
   83 		 */
   84 		toNumber(): number
   85 		{
   86 			if (this.unsigned)
   87 				return ((this.high >>> 0) * 
   88 					Long.TWO_PWR_32_DBL) + 
   89 				       (this.low >>> 0);
   90 			return this.high * Long.TWO_PWR_32_DBL + 
   91 				(this.low >>> 0);
   92 		};
   93 
   94 		/**
   95 		 * Similar to toNumber() except further reducing the
   96 		 * number to 32 bits of precision.
   97 		 * @return The Long converted to a number.
   98 		 */
   99 		toInt(): number
  100 		{
  101 			return this.unsigned ? this.low >>> 0 : this.low;
  102 		}
  103 
  104 		/**
  105 		 * Test whether the value is strictly <0.  For unsigned
  106 		 * values, this is always false.
  107 		 * @return Whether the value is strictly <0.
  108 		 */
  109 		isNegative(): boolean
  110 		{
  111 			return !this.unsigned && this.high < 0;
  112 		}
  113 
  114 		/**
  115 		 * Test whether the value is zero, regardless of sign.
  116 		 * @return Whether the value is zero.
  117 		 */
  118 		isZero(): boolean
  119 		{
  120 			return this.high === 0 && this.low === 0;
  121 		}
  122 
  123 		/**
  124 		 * Test whether the value is an odd number, regardless
  125 		 * of sign.
  126 		 * @return Whether the value is an odd number.
  127 		 */
  128 		isOdd(): boolean
  129 		{
  130 			return (this.low & 1) === 1;
  131 		}
  132 
  133 		/**
  134 		 * Test whether the value equals the given value.  This
  135 		 * is according to the numerical value, not the bit
  136 		 * pattern, so a negative signed value and a positive
  137 		 * signed value will be the same even if having the same
  138 		 * bit pattern.  The exception here is zero, which is
  139 		 * the same whether signed or not.
  140 		 * @return Whether the values are equal.
  141 		 */
  142 		eq(other: Long|number): boolean
  143 		{
  144 			const v: Long = !Long.isLong(other) ?
  145 				Long.fromNumber(<number>other) : <Long>other;
  146 
  147 			if (this.unsigned !== v.unsigned && 
  148 			    (this.high >>> 31) === 1 && 
  149 				    (v.high >>> 31) === 1)
  150 				return false;
  151 			return this.high === v.high && 
  152 				this.low === v.low;
  153 		}
  154 
  155 		/**
  156 		 * Negate a number (make it negative if positive,
  157 		 * positive if negative).  If zero, this converts to
  158 		 * zero of the other sign.
  159 		 * @return The negated value.
  160 		 */
  161 		neg(): Long
  162 		{
  163 			if (!this.unsigned && this.eq(Long.MIN_VALUE))
  164 				return Long.MIN_VALUE;
  165 			return this.not().add(Long.ONE);
  166 		}
  167 
  168 		/**
  169 		 * The bit-wise NOT of the value.  This retains the sign
  170 		 * of the original.
  171 		 * @return The bit-wise NOT of the value.
  172 		 */
  173 		not(): Long
  174 		{
  175 			return new Long(~this.low, 
  176 				~this.high, this.unsigned);
  177 		}
  178 
  179 		/**
  180 		 * The bit-wise AND of the value with the argument.
  181 		 * This retains the sign of the original.
  182 		 * @return The bit-wise AND of the value and argument.
  183 		 */
  184 		and(other: Long|number): Long
  185 		{
  186 			const v: Long = !Long.isLong(other) ?
  187 				Long.fromNumber(<number>other) : <Long>other;
  188 			return new Long(this.low & v.low, 
  189 					this.high & v.high, 
  190 					this.unsigned);
  191 		}
  192 
  193 		/**
  194 		 * The bit-wise OR of the value with the argument.
  195 		 * Sign is inherited from the source value.
  196 		 * @return The bit-wise OR of the value and argument.
  197 		 */
  198 		or(other: Long|number): Long 
  199 		{
  200 			const v: Long = !Long.isLong(other) ?
  201 				Long.fromNumber(<number>other) : <Long>other;
  202 			return new Long(this.low | v.low, 
  203 					this.high | v.high, 
  204 					this.unsigned);
  205 		}
  206 
  207 		/**
  208 		 * Compare the value with the argument and return their
  209 		 * sign comparison: 1 if the value is greater, -1 if
  210 		 * less, 0 if the same.  Zero is always the same as
  211 		 * zero, regardless the sign.
  212 		 * @return 0 if they are the same, 1 if the value is
  213 		 * greater, and -1 if the value is less.
  214 		 */
  215 		compare(other: Long|number): number
  216 		{
  217 			const v: Long = !Long.isLong(other) ?
  218 				Long.fromNumber(<number>other) : <Long>other;
  219 
  220 			if (this.eq(v))
  221 				return 0;
  222 
  223 			const thisNeg: boolean = this.isNegative();
  224 			const otherNeg: boolean = v.isNegative();
  225 
  226 			if (thisNeg && !otherNeg)
  227 				return -1;
  228 			if (!thisNeg && otherNeg)
  229 				return 1;
  230 
  231 			// At this point the sign bits are the same
  232 
  233 			if (!this.unsigned)
  234 				return this.sub(v).isNegative() ? -1 : 1;
  235 
  236 			// Both are positive if at least one is unsigned
  237 
  238 			return (v.high >>> 0) > (this.high >>> 0) || 
  239 				(v.high === this.high && 
  240 				 (v.low >>> 0) > (this.low >>> 0)) ?  -1 : 1;
  241 		};
  242 
  243 		/**
  244 		 * Left-shift the value by the given number of bits
  245 		 * (modulo 64).  Sign is inherited from the source
  246 		 * value.  The module means that shifting by 64 bits is
  247 		 * the same as zero, 65 the same as one, etc.  Shifting
  248 		 * by a negative number has undefined behaviour.
  249 		 * @return The left-shifted value.
  250 		 */
  251 		shl(numBits: Long|number): Long
  252 		{
  253 			let v: number = Long.isLong(numBits) ?
  254 				(<Long>numBits).toInt() : <number>numBits;
  255 
  256 			if ((v &= 63) === 0)
  257 				return this;
  258 			else if (v < 32)
  259 				return new Long
  260 					(this.low << v, 
  261 					 (this.high << v) | 
  262 					 (this.low >>> (32 - v)), 
  263 					 this.unsigned);
  264 			else
  265 				return new Long
  266 					(0, this.low << (v - 32), 
  267 					 this.unsigned);
  268 		}
  269 
  270 		/**
  271 		 * Arithmetic multiplication of the value to the argument.
  272 		 * Wrapping behaviour, including the identity at MAX_VALUE or
  273 		 * MIN_VALUE, is undefined.
  274 		 * @return The multiplied value.
  275 		 */
  276 		mul(tomul: Long|number): Long
  277 		{
  278 			const v: Long = !Long.isLong(tomul) ?
  279 				Long.fromNumber(<number>tomul) : <Long>tomul;
  280 
  281 			if (this.isZero() || v.isZero())
  282 				return Long.ZERO;
  283 			if (this.eq(Long.MIN_VALUE))
  284 				return v.isOdd() ? Long.MIN_VALUE : Long.ZERO;
  285 			if (v.eq(Long.MIN_VALUE))
  286 				return this.isOdd() ? Long.MIN_VALUE : Long.ZERO;
  287 
  288 			if (this.isNegative()) {
  289 				if (v.isNegative())
  290 					return this.neg().mul(v.neg());
  291 				else
  292 					return this.neg().mul(v).neg();
  293 			} else if (v.isNegative())
  294 				return this.mul(v.neg()).neg();
  295 
  296 			// Divide each long into 4 chunks of 16 bits,
  297 			// and then add up 4x4 products.  We can skip
  298 			// products that would overflow.
  299 
  300 			const a48: number = this.high >>> 16;
  301 			const a32: number = this.high & 0xFFFF;
  302 			const a16: number = this.low >>> 16;
  303 			const a00: number = this.low & 0xFFFF;
  304 
  305 			const b48: number = v.high >>> 16;
  306 			const b32: number = v.high & 0xFFFF;
  307 			const b16: number = v.low >>> 16;
  308 			const b00: number = v.low & 0xFFFF;
  309 
  310 			let c48: number = 0;
  311 			let c32: number = 0;
  312 			let c16: number = 0;
  313 			let c00: number = 0;
  314 
  315 			c00 += a00 * b00;
  316 			c16 += c00 >>> 16;
  317 			c00 &= 0xFFFF;
  318 			c16 += a16 * b00;
  319 			c32 += c16 >>> 16;
  320 			c16 &= 0xFFFF;
  321 			c16 += a00 * b16;
  322 			c32 += c16 >>> 16;
  323 			c16 &= 0xFFFF;
  324 			c32 += a32 * b00;
  325 			c48 += c32 >>> 16;
  326 			c32 &= 0xFFFF;
  327 			c32 += a16 * b16;
  328 			c48 += c32 >>> 16;
  329 			c32 &= 0xFFFF;
  330 			c32 += a00 * b32;
  331 			c48 += c32 >>> 16;
  332 			c32 &= 0xFFFF;
  333 			c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48;
  334 			c48 &= 0xFFFF;
  335 
  336 			return new Long
  337 				((c16 << 16) | c00, (c48 << 16) | c32,
  338 				 this.unsigned);
  339 		}
  340 
  341 		/**
  342 		 * Alias for adding the negative of the argument to the
  343 		 * value.
  344 		 * @return The difference of the values.
  345 		 */
  346 		sub(tosub: Long|number): Long
  347 		{
  348 			const v: Long = !Long.isLong(tosub) ?
  349 				Long.fromNumber(<number>tosub) : <Long>tosub;
  350 			return this.add(v.neg());
  351 		};
  352 
  353 		/**
  354 		 * Add the argument to the value.
  355 		 * @return The addition of the values.
  356 		 */
  357 		add(toadd: Long|number): Long
  358 		{
  359 			const v: Long = !Long.isLong(toadd) ?
  360 				Long.fromNumber(<number>toadd) : 
  361 				<Long>toadd;
  362 
  363 			// Divide each number into 4 chunks of 16 bits,
  364 			// and then sum the chunks.
  365 
  366 			const a48: number = this.high >>> 16;
  367 			const a32: number = this.high & 0xFFFF;
  368 			const a16: number = this.low >>> 16;
  369 			const a00: number = this.low & 0xFFFF;
  370 
  371 			const b48: number = v.high >>> 16;
  372 			const b32: number = v.high & 0xFFFF;
  373 			const b16: number = v.low >>> 16;
  374 			const b00: number = v.low & 0xFFFF;
  375 
  376 			let c48: number = 0;
  377 			let c32: number = 0;
  378 			let c16: number = 0;
  379 			let c00: number = 0;
  380 
  381 			c00 += a00 + b00;
  382 			c16 += c00 >>> 16;
  383 			c00 &= 0xFFFF;
  384 			c16 += a16 + b16;
  385 			c32 += c16 >>> 16;
  386 			c16 &= 0xFFFF;
  387 			c32 += a32 + b32;
  388 			c48 += c32 >>> 16;
  389 			c32 &= 0xFFFF;
  390 			c48 += a48 + b48;
  391 			c48 &= 0xFFFF;
  392 
  393 			return new Long
  394 				((c16 << 16) | c00, (c48 << 16) | c32,
  395 				 this.unsigned);
  396 		}
  397 
  398 		/**
  399 		 * Attempt to convert from a Long, number, or string.  Failure
  400 		 * to convert, whether by syntax, not being defined, or null,
  401 		 * will return null.
  402 		 * @return The value or null on failure.
  403 		 */
  404 		static fromValue(val: any, unsigned?: boolean): Long|null
  405 		{
  406 			if (typeof val === 'undefined')
  407 				return null;
  408 			if (typeof val === 'number')
  409 				return Long.fromNumber
  410 					(<number>val, unsigned);
  411 			if (typeof val === 'string')
  412 				return Long.fromString
  413 					(<string>val, unsigned);
  414 			if (Long.isLong(val))
  415 				return <Long>val;
  416 			return null;
  417 		}
  418 
  419 		/**
  420 		 * Like fromValue(), except passing through on undefined values.
  421 		 * @return The value, null on failure, or undefined if not
  422 		 * defined.
  423 		 */
  424 		static fromValueUndef(val: any, unsigned?: boolean): Long|null|undefined
  425 		{
  426 			if (typeof val === 'undefined')
  427 				return undefined;
  428 			return Long.fromValue(val, unsigned);
  429 		}
  430 
  431 		/**
  432 		 * Convert from a number to the Long representation of the
  433 		 * value.  If NaN, returns zero or unsigned zero as applicable.
  434 		 * If negative and wanting unsigned, bound at zero.  Otherwise
  435 		 * bound to a 64-bit integer size.
  436 		 * @return The value.
  437 		 */
  438 		static fromNumber(value: number, unsigned?: boolean): Long
  439 		{
  440 			const usgn: boolean =
  441 				(typeof unsigned === 'undefined') ?
  442 				false : unsigned;
  443 
  444 			if (isNaN(value))
  445 				return usgn ? Long.UZERO : Long.ZERO;
  446 
  447 			if (usgn) {
  448 				if (value < 0)
  449 					return Long.UZERO;
  450 				if (value >= Long.TWO_PWR_64_DBL)
  451 					return Long.MAX_UNSIGNED_VALUE;
  452 			} else {
  453 				if (value <= -Long.TWO_PWR_63_DBL)
  454 					return Long.MIN_VALUE;
  455 				if (value + 1 >= Long.TWO_PWR_63_DBL)
  456 					return Long.MAX_VALUE;
  457 			}
  458 
  459 			if (value < 0)
  460 				return Long.fromNumber
  461 					(-value, unsigned).neg();
  462 
  463 			return new Long
  464 				((value % Long.TWO_PWR_32_DBL) | 0, 
  465 				 (value / Long.TWO_PWR_32_DBL) | 0, 
  466 				 unsigned);
  467 		}
  468 
  469 		/**
  470 		 * Like fromString(), except returning failed conversions as a
  471 		 * zero value.
  472 		 * @return The value.
  473 		 */
  474 		static fromStringZero(str: string, unsigned?: boolean): Long
  475 		{
  476 			const val: Long|null = Long.fromString(str, unsigned);
  477 			return val === null ? Long.ZERO : val;
  478 		}
  479 
  480 		/**
  481 		 * Convert from a string representation of a number to a Long.
  482 		 * The string may have an optional leading "-" followed by
  483 		 * digits.  This does not accept NaN, Infinity, or other
  484 		 * symbols.
  485 		 * @return The value or null on failure.
  486 		 */
  487 		static fromString(str: string, unsigned?: boolean): Long | null
  488 		{
  489 			const usgn: boolean =
  490 				(typeof unsigned === 'undefined') ?
  491 				false : unsigned;
  492 			const hyph: number = str.indexOf('-');
  493 			const radixToPower: Long = Long.TEN_TO_EIGHT;
  494 			let result: Long = Long.ZERO;
  495 
  496 			if (str.length === 0 || hyph > 0 ||
  497 			    str === 'NaN' || str === 'Infinity' || 
  498 			    str === '+Infinity' || str === '-Infinity')
  499 				return null;
  500 
  501 			if (hyph === 0) {
  502 				const nresult: Long|null = 
  503 					Long.fromString
  504 					(str.substring(1), usgn);
  505 				if (nresult === null)
  506 					return null;
  507 				return nresult.neg();
  508 			}
  509 
  510 			if (!str.match(/^[0-9]+$/))
  511 				return null;
  512 
  513 			// Do several (8) digits each time through the
  514 			// loop, so as to  minimize the calls to the
  515 			// very expensive emulated div.
  516 
  517 			for (let i: number = 0; i < str.length; i += 8) {
  518 				const size: number = 
  519 					Math.min(8, str.length - i);
  520 				const value: number = 
  521 					parseInt(str.substring(i, i + size), 10);
  522 				if (isNaN(value))
  523 					return null;
  524 				if (size < 8) {
  525 					const power: Long = 
  526 						Long.fromNumber
  527 						(Math.pow(10, size));
  528 					result = result.mul(power).add
  529 						(Long.fromNumber(value));
  530 				} else {
  531 					result = result.mul
  532 						(radixToPower);
  533 					result = result.add
  534 						(Long.fromNumber(value));
  535 				}
  536 			}
  537 			return new Long(result.low, result.high, usgn);
  538 		}
  539 	}
  540 
  541 	/**
  542 	 * Labels ("jslabel" in ort(5)) may have multiple languages.
  543 	 * This maps a language name to a translated string.
  544 	 */
  545 	interface langmap
  546 	{
  547 		[lang: string]: string
  548 	};
  549 
  550 	/**
  551 	 * Resolve a set of translated strings into a single one
  552 	 * depending upon the current language.
  553 	 * @param vals All translations of a given word.
  554 	 * @return The word in the current language (or the default)
  555 	 * or an empty string on failure.
  556 	 * @internal
  557 	 */
  558 	function _strlang(vals: langmap): string
  559 	{
  560 		const lang = document.documentElement.lang;
  561 		if (lang !== null && lang in vals)
  562 			return vals[lang];
  563 		else if ('_default' in vals)
  564 			return vals['_default'];
  565 		else
  566 			return '';
  567 	}
  568 
  569 	/**
  570 	 * Language replacement conditional upon the label (**jslabel**
  571 	 * in the configuration).  Like {@link _replcl} with inclusion
  572 	 * set to false.
  573 	 * @param e The root of the DOM tree in which we query for 
  574 	 * elements to fill into.
  575 	 * @param name The class name we search for within the root (not 
  576 	 * inclusive).
  577 	 * @param vals All possible translations.
  578 	 * @internal
  579 	 */
  580 	function _replcllang(e: HTMLElement, name:string, vals: langmap): void
  581 	{
  582 		_replcl(e, name, _strlang(vals), false);
  583 	}
  584 
  585 	/**
  586 	 * Language replacement conditional upon the label (**jslabel**
  587 	 * in the configuration). Like {@link _repl}.
  588 	 * @param e The root of the DOM tree in which we query for 
  589 	 * elements to fill into.
  590 	 * @param vals All possible translations.
  591 	 * @internal
  592 	 */
  593 	function _repllang(e: HTMLElement, vals: langmap): void
  594 	{
  595 		_repl(e, _strlang(vals));
  596 	}
  597 
  598 	/**
  599 	 * Set the attribute of an element.
  600 	 * @param e The element whose attribute to set.
  601 	 * @param attr The attribute name.
  602 	 * @param text The attribute value.
  603 	 * @internal
  604 	 */
  605 	function _attr(e: HTMLElement, attr: string, text: string): void
  606 	{
  607 		e.setAttribute(attr, text);
  608 	}
  609 
  610 	/**
  611 	 * Set attributes for all elements matching a class.
  612 	 * @internal
  613 	 */
  614 	function _attrcl(e: HTMLElement, attr: string, name: string, text: string,
  615 		inc: boolean): void
  616 	{
  617 		for (const elem of _elemList(e, name, inc))
  618 			_attr(elem, attr, text);
  619 	}
  620 
  621 	/**
  622 	 * Get all elements beneath (possibly including) a root matching
  623 	 * the given class.
  624 	 * @internal
  625 	 */
  626 	function _elemList(e: HTMLElement|null, cls: string, inc: boolean): HTMLElement[]
  627 	{
  628 		if (e === null)
  629 			return [];
  630 		const a = Array.prototype.filter.call(
  631 			e.getElementsByClassName(cls),
  632 			elem => elem instanceof HTMLElement,
  633 		) as HTMLElement[];
  634 		if (inc && e.classList.contains(cls))
  635 			a.push(e);
  636 		return a;
  637 	}
  638 
  639 	/**
  640 	 * Replace all children of an element with text.
  641 	 * @internal
  642 	 */
  643 	function _repl(e: HTMLElement, text: string): void
  644 	{
  645 		e.replaceChildren(document.createTextNode(text));
  646 	}
  647 
  648 	/**
  649 	 * Replace children of elements matching class with text.
  650 	 * @internal
  651 	 */
  652 	function _replcl(e: HTMLElement, name: string, text: string, inc: boolean):
  653 		void
  654 	{
  655 		for (const elem of _elemList(e, name, inc))
  656 			_repl(elem, text);
  657 	}
  658 
  659 	/**
  660 	 * Add class to class list if it doesn't exist.
  661 	 * @internal
  662 	 */
  663 	function _classadd(e: HTMLElement, name: string): HTMLElement
  664 	{
  665 		if (!e.classList.contains(name))
  666 			e.classList.add(name);
  667 		return(e);
  668 	}
  669 
  670 	/**
  671 	 * Add class if doesn't exist to all elements with class name.
  672 	 * @internal
  673 	 */
  674 	function _classaddcl(e: HTMLElement, name: string, cls: string,
  675 		inc: boolean): void
  676 	{
  677 		for (const elem of _elemList(e, name, inc))
  678 			_classadd(elem, cls);
  679 	}
  680 
  681 	/**
  682 	 * "Hide" element by adding *hide* class.
  683 	 * @internal
  684 	 */
  685 	function _hide(e: HTMLElement): HTMLElement
  686 	{
  687 		if (!e.classList.contains('hide'))
  688 			e.classList.add('hide');
  689 		return e;
  690 	}
  691 
  692 	/**
  693 	 * "Hide" all elements matching class by adding *hide* class.
  694 	 * @internal
  695 	 */
  696 	function _hidecl(e: HTMLElement, name: string, inc: boolean): void
  697 	{
  698 		for (const elem of _elemList(e, name, inc))
  699 			_hide(elem);
  700 	}
  701 
  702 	/**
  703 	 * "Show" element by removing *hide* class.
  704 	 * @internal
  705 	 */
  706 	function _show(e: HTMLElement): HTMLElement
  707 	{
  708 		if (e.classList.contains('hide'))
  709 			e.classList.remove('hide');
  710 		return e;
  711 	}
  712 
  713 	/**
  714 	 * "Show" all elements matching class by removing *hide* class.
  715 	 * @internal
  716 	 */
  717 	function _showcl(e: HTMLElement, name: string, inc: boolean): void
  718 	{
  719 		for (const elem of _elemList(e, name, inc))
  720 			_show(elem);
  721 	}
  722 
  723 	/**
  724 	 * Check input elements (that is, set the attribute `checked` to
  725 	 * the value `checked`) for all elements of class
  726 	 * `fname-value-checked` whose value matches the given.  The
  727 	 * checked status is removed for each item scanned.
  728 	 * A null value never matches.
  729 	 * @param e Root of tree scanned for elements.
  730 	 * @param fname Structure name, '-', field name.
  731 	 * @param val The value to test for.
  732 	 * @param inc Include root in scanning for elements.
  733 	 * @internal
  734 	 */
  735 	function _fillValueChecked(e: HTMLElement, fname: string,
  736 		val: number|string|null, inc: boolean): void
  737 	{
  738 		for (const elem of
  739 		     _elemList(e, fname + '-value-checked', inc)) {
  740 			const inp = elem as HTMLInputElement;
  741 			const attrval = inp.value;
  742 			inp.removeAttribute('checked');
  743 			if (val === null || attrval === null)
  744 				continue;
  745 			if (val.toString() === attrval)
  746 				inp.setAttribute('checked', 'checked');
  747 		}
  748 	}
  749 
  750 	/**
  751 	 * Take all `<option>` elements under the root (non-inclusive)
  752 	 * and sets or unsets the `selected` attribute depending upon
  753 	 * whether it matches the object's value.
  754 	 * A null value never matches.
  755 	 * @param e Root of tree scanned for elements.
  756 	 * @param val The value to test for.
  757 	 * @internal
  758 	 */
  759 	function _fillValueSelect(e: HTMLElement,
  760 		val: number|string|null): void
  761 	{
  762 		const list = Array.from(e.getElementsByTagName('option'));
  763 		for (const elem of list) {
  764 			const opt = elem as HTMLOptionElement;
  765 			const attrval = opt.value;
  766 			opt.removeAttribute('selected');
  767 			if (val === null || attrval === null)
  768 				continue;
  769 			if (val.toString() === attrval)
  770 				opt.setAttribute('selected', 'selected');
  771 		}
  772 	}
  773 
  774 	/**
  775 	 * Fill in ISO-8601 dates.
  776 	 * Does nothing for null or unexported date.
  777 	 * @param e Root of tree scanned for elements.
  778 	 * @param fname Structure name, '-', field name.
  779 	 * @param val Epoch date itself.
  780 	 * @param inc Include root in scanning for elements.
  781 	 * @internal
  782 	 */
  783 	function _fillDateValue(e: HTMLElement, fname: string,
  784 		val: string|number|null|undefined, inc: boolean): void
  785 	{
  786 		const v = Long.fromValue(val);
  787 		if (v === null)
  788 			return;
  789 
  790 		const d = new Date();
  791 		d.setTime(v.toNumber() * 1000);
  792 
  793 		/* Make sure to zero-pad the digits. */
  794 
  795 		const year = d.getFullYear();
  796 		const mo = d.getMonth() + 1;
  797 		const day = d.getDate();
  798 		const full = year + '-' +
  799 			(mo < 10 ? '0' : '') + mo + '-' +
  800 			(day < 10 ? '0' : '') + day;
  801 		_attrcl(e, 'value', fname + '-date-value', full, inc);
  802 		_replcl(e, fname + '-date-text', full, inc);
  803 	}
  804 
  805 	/**
  806 	 * Check input elements (that is, set the attribute `checked` to
  807 	 * the value `checked`) for elements with class 
  808 	 * `fname-value-checked` whose non-null, numeric value as a bit index
  809 	 * is set in the bit-field given as input.
  810 	 * A null value never matches.
  811 	 * @param e Root of tree scanned for elements.
  812 	 * @param fname Structure name, '-', field name.
  813 	 * @param val Bit-field to test for.
  814 	 * @param inc Include root in scanning for elements.
  815 	 * @internal
  816 	 */
  817 	function _fillBitsChecked(e: HTMLElement, fname: string,
  818 		 val: string|number|null|undefined, inc: boolean): void
  819 	{
  820 		const lval = Long.fromValueUndef(val);
  821 		if (typeof lval === 'undefined')
  822 			return;
  823 		for (const elem of _elemList(e, fname + '-bits-checked', inc)) {
  824 			const inp = elem as HTMLInputElement;
  825 			const attrval: string|null = inp.value;
  826 			inp.removeAttribute('checked');
  827 			if (lval === null || attrval === null)
  828 				continue;
  829 
  830 			/*
  831 			 * This would be better served with
  832 			 * Number.isInteger(), but we don't want to
  833 			 * assume ES6.
  834 			 */
  835 
  836 			const v = Number(attrval);
  837 			if (isNaN(v))
  838 				continue;
  839 			if (!(isFinite(v) && Math.floor(v) === v))
  840 				continue;
  841 			if (v < 0 || v > 64)
  842 				continue;
  843 
  844 			if ((v === 0 && lval.isZero()) ||
  845 			    !Long.ONE.shl(v - 1).and(lval).isZero()) {
  846 				inp.setAttribute('checked', 'checked');
  847 			}
  848 		}
  849 	}
  850 
  851 	/**
  852 	 * Fill a structure field.  This first does the has/no class
  853 	 * setting for null values, then optionally returns if null
  854 	 * (running the custom fields first), otherwise the generic
  855 	 * text/value/etc fields, then finally the custom fields.
  856 	 * @param e Root of the DOM tree filled into.
  857 	 * @param strct Name of the structure filling in.
  858 	 * @param name The name of the field.
  859 	 * @param custom Custom callback functions.
  860 	 * @param obj The data itself.
  861 	 * @param inc Whether to include the root element in looking
  862 	 * for elements to fill. Nested structures are always filled 
  863 	 * non-inclusively.
  864 	 * @param cannull Whether the data may be null.
  865 	 * @param sub If the data object is a nested structure
  866 	 * interface, the allocated class of that interface.
  867 	 * @internal
  868 	 */
  869 	function _fillField(e: HTMLElement, strct: string, name: string,
  870 		custom: DataCallbacks|null, obj: any, inc: boolean,
  871 		cannull: boolean, sub: any): void
  872 	{
  873 		const fname = strct + '-' + name;
  874 
  875 		/* Don't do anything if we're not defined. */
  876 
  877 		if (typeof(obj) === 'undefined')
  878 			return;
  879 
  880 		/* First handle our has/no null situation. */
  881 
  882 		if (cannull) {
  883 			if (obj === null) {
  884 				_hidecl(e, strct + '-has-' + name, inc);
  885 				_showcl(e, strct + '-no-' + name, inc);
  886 			} else {
  887 				_showcl(e, strct + '-has-' + name, inc);
  888 				_hidecl(e, strct + '-no-' + name, inc);
  889 			}
  890 		}
  891 
  892 		/* Don't process null values that can be null. */
  893 
  894 		if (cannull && obj === null) {
  895 			if (custom !== null && fname in custom) {
  896 				if (Array.isArray(custom[fname])) {
  897 					for (const fn of custom[fname])
  898 						fn(e, fname, null);
  899 				} else
  900 					custom[fname](e, fname, null);
  901 			}
  902 			return;
  903 		}
  904 
  905 		/* 
  906 		 * Non-null non-structs.
  907 		 * Note that "sub" is never undefined because that would
  908 		 * otherwise be caught in the "typeof obj" guard above.
  909 		 */
  910 
  911 		if (sub !== null) {
  912 			for (const elem of
  913 			     _elemList(e, fname + '-obj', inc))
  914 				sub.fillInner(elem as HTMLElement, custom);
  915 		} else {
  916 			for (const elem of
  917 			     _elemList(e, fname + '-enum-select', inc))
  918 				_fillValueSelect(elem, obj);
  919 			_replcl(e, fname + '-text', obj, inc);
  920 			_attrcl(e, 'value', fname + '-value', obj, inc);
  921 			_fillValueChecked(e, fname, obj, inc);
  922 		}
  923 
  924 		/* Lastly, handle the custom callback. */
  925 
  926 		if (custom !== null && fname in custom) {
  927 			if (Array.isArray(custom[fname])) {
  928 				for (const fn of custom[fname])
  929 					fn(e, fname, obj);
  930 			} else
  931 				custom[fname](e, fname, obj);
  932 		}
  933 	}
  934 
  935 	export type DCbstring = (e: HTMLElement,
  936 		name: string, val: string) => void;
  937 	export type DCbstringNull = (e: HTMLElement,
  938 		name: string, val: string|null) => void;
  939 	export type DCbinteger = (e: HTMLElement,
  940 		name: string, val: string|number) => void;
  941 	export type DCbintegerNull = (e: HTMLElement,
  942 		name: string, val: string|number|null) => void;
  943 	export type DCbnumber = (e: HTMLElement,
  944 		name: string, val: number) => void;
  945 	export type DCbnumberNull = (e: HTMLElement,
  946 		name: string, val: number|null) => void;
  947 	export type DCbStructcompany = (e: HTMLElement,
  948 		name: string, val: companyData|null) => void;
  949 	export type DCbStructuser = (e: HTMLElement,
  950 		name: string, val: userData|null) => void;
  951 	export type DCbStructsession = (e: HTMLElement,
  952 		name: string, val: sessionData|null) => void;
  953 
  954 	/**
  955 	 * All possible custom callbacks for this ort configuration.
  956 	 */
  957 	export interface DataCallbacks
  958 	{
  959 		[key: string]: any;
  960 		'company'?: DCbStructcompany|DCbStructcompany[];
  961 		'company-name'?: DCbstring|DCbstring[];
  962 		'company-id'?: DCbinteger|DCbinteger[];
  963 		'company-somenum'?: DCbintegerNull|DCbintegerNull[];
  964 		'user'?: DCbStructuser|DCbStructuser[];
  965 		'user-company'?: DCbStructcompany|DCbStructcompany[];
  966 		'user-cid'?: DCbinteger|DCbinteger[];
  967 		'user-sex'?: DCbinteger|DCbinteger[];
  968 		'user-email'?: DCbstring|DCbstring[];
  969 		'user-image'?: DCbstringNull|DCbstringNull[];
  970 		'user-name'?: DCbstring|DCbstring[];
  971 		'user-uid'?: DCbinteger|DCbinteger[];
  972 		'session'?: DCbStructsession|DCbStructsession[];
  973 		'session-user'?: DCbStructuser|DCbStructuser[];
  974 		'session-userid'?: DCbinteger|DCbinteger[];
  975 		'session-token'?: DCbinteger|DCbinteger[];
  976 		'session-mtime'?: DCbinteger|DCbinteger[];
  977 		'session-id'?: DCbinteger|DCbinteger[];
  978 	}
  979 
  980 	/**
  981 	 * Controlling organisation.
  982 	 */
  983 	export interface companyData
  984 	{
  985 		/**
  986 		 * Name of the organisation.
  987 		 */
  988 		name: string;
  989 		id: string|number;
  990 		/**
  991 		 * Simply a check for null values.
  992 		 */
  993 		somenum: string|number;
  994 	}
  995 
  996 	/**
  997 	 * A regular user.
  998 	 */
  999 	export interface userData
 1000 	{
 1001 		/**
 1002 		 * This struct will be filled in from an inner join
 1003 		 *     on the "cid" variable.
 1004 		 */
 1005 		company: companyData;
 1006 		/**
 1007 		 * A foreign key reference.
 1008 		 */
 1009 		cid: string|number;
 1010 		/**
 1011 		 * User's birth sex.
 1012 		 */
 1013 		sex: string|number;
 1014 		/**
 1015 		 * Unique e-mail address.
 1016 		 */
 1017 		email: string;
 1018 		/**
 1019 		 * A PNG image or something.
 1020 		 */
 1021 		image: string;
 1022 		/**
 1023 		 * User's full name.
 1024 		 */
 1025 		name: string;
 1026 		uid: string|number;
 1027 	}
 1028 
 1029 	/**
 1030 	 * Authenticated session.
 1031 	 */
 1032 	export interface sessionData
 1033 	{
 1034 		user: userData;
 1035 		/**
 1036 		 * Associated user.
 1037 		 */
 1038 		userid: string|number;
 1039 		/**
 1040 		 * Random cookie.
 1041 		 */
 1042 		token: string|number;
 1043 		mtime: string|number;
 1044 		id: string|number;
 1045 	}
 1046 
 1047 	/**
 1048 	 * Writes {@link companyData} into a DOM tree.
 1049 	 */
 1050 	export class company {
 1051 		readonly obj: companyData|companyData[];
 1052 		/**
 1053 		 * @param obj The object(s) to write.
 1054 		 */
 1055 		constructor(o: companyData|companyData[])
 1056 		{
 1057 			this.obj = o;
 1058 		}
 1059 
 1060 		/**
 1061 		 * Writes {@link companyData} into the given element. If 
 1062 		 * constructed with an array, the first element is used.  
 1063 		 * Elements within (and including) the element having the 
 1064 		 * following classes are manipulated as follows:
 1065 		 * 
 1066 		 * - `company-name-enum-select`: sets or unsets the `selected` 
 1067 		 * attribute for non-inclusive descendent `<option>` elements 
 1068 		 * depending on whether the value matches
 1069 		 * - `company-name-value-checked`: sets or unsets the `checked` 
 1070 		 * attribute depending on whether the value matches
 1071 		 * - `company-name-text`: replace contents with **name** data
 1072 		 * - `company-name-value`: replace `value` attribute with 
 1073 		 * **name** data
 1074 		 * - `company-id-enum-select`: sets or unsets the `selected` 
 1075 		 * attribute for non-inclusive descendent `<option>` elements 
 1076 		 * depending on whether the value matches
 1077 		 * - `company-id-value-checked`: sets or unsets the `checked` 
 1078 		 * attribute depending on whether the value matches
 1079 		 * - `company-id-text`: replace contents with **id** data
 1080 		 * - `company-id-value`: replace `value` attribute with **id** 
 1081 		 * data
 1082 		 * - `company-has-somenum`: *hide* class removed if value is not 
 1083 		 * null, otherwise it is added
 1084 		 * - `company-no-somenum`: *hide* class added if value is not 
 1085 		 * null, otherwise it is removed
 1086 		 * - `company-somenum-enum-select`: sets or unsets the `selected` 
 1087 		 * attribute for non-inclusive descendent `<option>` elements 
 1088 		 * depending on whether the value matches (if non-null)
 1089 		 * - `company-somenum-value-checked`: sets or unsets the 
 1090 		 * `checked` attribute depending on whether the value matches (if 
 1091 		 * non-null)
 1092 		 * - `company-somenum-text`: replace contents with **somenum** 
 1093 		 * data (if non-null)
 1094 		 * - `company-somenum-value`: replace `value` attribute with 
 1095 		 * **somenum** data (if non-null)
 1096 		 * 
 1097 		 * @param e The DOM element.
 1098 		 * @param custom The dictionary of functions keyed by structure 
 1099 		 * and field name (e.g., *foo** structure, **bar** field would be 
 1100 		 * `foo-bar`). The value is a function for custom handling that 
 1101 		 * accepts the 'e' value, the name of the structure-field, and 
 1102 		 * the value of the structure and field. You may also specify an 
 1103 		 * array of functions instead of a singleton. These callbacks are 
 1104 		 * invoked *after* the generic classes are filled.
 1105 		 */
 1106 		fill(e: HTMLElement|null, custom?: DataCallbacks|null): void
 1107 		{
 1108 			if (e !== null)
 1109 				this._fill(e, this.obj, true, custom);
 1110 		}
 1111 
 1112 		/**
 1113 		 * Like {@link fill} but not including the passed-in element.
 1114 		 * @param e The DOM element.
 1115 		 * @param custom Custom handler dictionary (see {@link fill} for 
 1116 		 * details).
 1117 		 */
 1118 		fillInner(e: HTMLElement|null, custom?: DataCallbacks|null): 
 1119 			void
 1120 		{
 1121 			if (e !== null)
 1122 				this._fill(e, this.obj, false, custom);
 1123 		}
 1124 
 1125 		/**
 1126 		 * Like {@link fill} but instead of accepting a single element to 
 1127 		 * fill, filling into all elements (inclusive) matching the given 
 1128 		 * class name beneath (inclusive) the element.
 1129 		 * @param e The DOM element.
 1130 		 * @param name Name of the class to fill.
 1131 		 * @param custom Custom handler dictionary (see {@link fill} for 
 1132 		 * details).
 1133 		 */
 1134 		fillByClass(e: HTMLElement|null, name: string, 
 1135 			custom?: DataCallbacks|null): void
 1136 		{
 1137 			if (e !== null)
 1138 				this._fillByClass(e, name, true, custom);
 1139 		}
 1140 
 1141 		/**
 1142 		 * Like {@link fillByClass} but not inclusive the root element 
 1143 		 * and class matches.
 1144 		 * @param e The DOM element.
 1145 		 * @param name Name of the class to fill.
 1146 		 * @param custom Custom handler dictionary (see {@link fill} for 
 1147 		 * details).
 1148 		 */
 1149 		fillInnerByClass(e: HTMLElement|null, name: string, 
 1150 			custom?: DataCallbacks|null): void
 1151 		{
 1152 			if (e !== null)
 1153 				this._fillByClass(e, name, false, custom);
 1154 		}
 1155 
 1156 		private _fill(e: HTMLElement, obj: companyData|companyData[], 
 1157 			inc: boolean, custom?: DataCallbacks|null): 
 1158 			void
 1159 		{
 1160 			if (Array.isArray(obj) && obj.length === 0)
 1161 				return;
 1162 			const o = Array.isArray(obj) ? obj[0] : obj;
 1163 			if (typeof(custom) === 'undefined')
 1164 				custom = null;
 1165 			_fillField(e, 'company', 'name', custom,
 1166 				o.name, inc, false,null);
 1167 			_fillField(e, 'company', 'id', custom, o.id, inc,
 1168 				false,null);
 1169 			_fillField(e, 'company', 'somenum', custom,
 1170 				o.somenum, inc, true,null);
 1171 			if (custom !== null &&
 1172 			    typeof(custom['company']) !== 'undefined') {
 1173 				if (Array.isArray(custom['company'])) {
 1174 					for (const fn of custom['company'])
 1175 						fn(e, 'company', o);
 1176 				} else
 1177 					custom['company'](e, 'company', o);
 1178 			}
 1179 		}
 1180 
 1181 		private _fillByClass(e: HTMLElement, name: string, inc: boolean, 
 1182 			custom?: DataCallbacks|null): void
 1183 		{
 1184 			for (const elem of _elemList(e, name, inc))
 1185 				this._fill(elem, this.obj, inc, custom);
 1186 		}
 1187 
 1188 		/**
 1189 		 * Like {@link fillArray}, but hiding an element if the array is 
 1190 		 * empty or null.
 1191 		 * @param e The DOM element.
 1192 		 * @param tohide DOM element to hide.
 1193 		 * @param o The array (or object) to fill.
 1194 		 * @param custom Custom handler dictionary (see {@link fill}).
 1195 		 */
 1196 		fillArrayOrHide(e: HTMLElement|null, tohide: HTMLElement|null, 
 1197 			custom?: DataCallbacks|null): void
 1198 		{
 1199 			const len = (this.obj === null) ? 0 :
 1200 				Array.isArray(this.obj) ? this.obj.length :
 1201 				1;
 1202 			if (e !== null)
 1203 				_hide(e);
 1204 			if (tohide !== null)
 1205 				_show(tohide);
 1206 			this.fillArray(e, custom);
 1207 			if (tohide !== null && len === 0)
 1208 				_hide(tohide);
 1209 		}
 1210 
 1211 		/**
 1212 		 * Like {@link fillArray}, but showing an element if the array is 
 1213 		 * empty or null.
 1214 		 * @param e The DOM element.
 1215 		 * @param toshow The DOM element to show.
 1216 		 * @param o The array or object to fill.
 1217 		 * @param custom Custom handler dictionary (see {@link fill}).
 1218 		 */
 1219 		fillArrayOrShow(e: HTMLElement|null, toshow: HTMLElement|null, 
 1220 			custom?: DataCallbacks|null): void
 1221 		{
 1222 			const len = (this.obj === null) ? 0 :
 1223 				Array.isArray(this.obj) ? this.obj.length :
 1224 				1;
 1225 			if (e !== null)
 1226 				_hide(e);
 1227 			if (toshow !== null)
 1228 				_hide(toshow);
 1229 			this.fillArray(e, custom);
 1230 			if (toshow !== null && len === 0)
 1231 				_show(toshow);
 1232 		}
 1233 
 1234 		/**
 1235 		 * Like {@link fill} but for an array. If the data is not an 
 1236 		 * array, it is remapped as an array of one. This will save the 
 1237 		 * first element within 'e', remove all children of 'e', then 
 1238 		 * repeatedly clone the saved element and re-append it, filling 
 1239 		 * in the cloned subtree with the array (inclusive of the subtree 
 1240 		 * root). If the input array is empty or null, 'e' is hidden by 
 1241 		 * using the *hide* class. Otherwise, the *hide* class is 
 1242 		 * removed.
 1243 		 * @param e The DOM element.
 1244 		 * @param custom Custom handler dictionary (see {@link fill}).
 1245 		 */
 1246 		fillArray(e: HTMLElement|null, custom?: DataCallbacks|null): 
 1247 			void
 1248 		{
 1249 			const o = Array.isArray(this.obj) ?
 1250 				this.obj : [this.obj];
 1251 			if (e === null || e.children.length === 0)
 1252 				return;
 1253 			_hide(e);
 1254 			if (o.length === 0 || this.obj === null)
 1255 				return;
 1256 			_show(e);
 1257 			const row = e.children[0];
 1258 			e.replaceChildren();
 1259 			for (const obj of o) {
 1260 				const cln = <HTMLElement>row.cloneNode(true);
 1261 				e.append(cln);
 1262 				this._fill(cln, obj, true, custom);
 1263 			}
 1264 		}
 1265 
 1266 		/**
 1267 		 * Like {@link fillArray} but instead of accepting a single 
 1268 		 * element to fill, filling all elements by class name beneath 
 1269 		 * the given root (non-inclusive).
 1270 		 * @param e The DOM element.
 1271 		 * @param name Name of the class to fill.
 1272 		 * @param custom Custom handler dictionary (see {@link fill} for 
 1273 		 * details).
 1274 		 */
 1275 		fillArrayByClass(e: HTMLElement|null, name: string, 
 1276 			custom?: DataCallbacks|null): void
 1277 		{
 1278 			for (const elem of _elemList(e, name, false))
 1279 				this.fillArray(elem, custom);
 1280 		}
 1281 
 1282 	}
 1283 
 1284 	/**
 1285 	 * Writes {@link userData} into a DOM tree.
 1286 	 */
 1287 	export class user {
 1288 		readonly obj: userData|userData[];
 1289 		/**
 1290 		 * @param obj The object(s) to write.
 1291 		 */
 1292 		constructor(o: userData|userData[])
 1293 		{
 1294 			this.obj = o;
 1295 		}
 1296 
 1297 		/**
 1298 		 * Writes {@link userData} into the given element. If constructed 
 1299 		 * with an array, the first element is used.  Elements within 
 1300 		 * (and including) the element having the following classes are 
 1301 		 * manipulated as follows:
 1302 		 * 
 1303 		 * - `user-company-obj`: invoke {@link company#fillInner} with 
 1304 		 * **company** data
 1305 		 * - `user-cid-enum-select`: sets or unsets the `selected` 
 1306 		 * attribute for non-inclusive descendent `<option>` elements 
 1307 		 * depending on whether the value matches
 1308 		 * - `user-cid-value-checked`: sets or unsets the `checked` 
 1309 		 * attribute depending on whether the value matches
 1310 		 * - `user-cid-text`: replace contents with **cid** data
 1311 		 * - `user-cid-value`: replace `value` attribute with **cid** 
 1312 		 * data
 1313 		 * - `user-sex-enum-select`: sets or unsets the `selected` 
 1314 		 * attribute for non-inclusive descendent `<option>` elements 
 1315 		 * depending on whether the value matches
 1316 		 * - `user-sex-value-checked`: sets or unsets the `checked` 
 1317 		 * attribute depending on whether the value matches
 1318 		 * - `user-sex-text`: replace contents with **sex** data
 1319 		 * - `user-sex-value`: replace `value` attribute with **sex** 
 1320 		 * data
 1321 		 * - `user-email-enum-select`: sets or unsets the `selected` 
 1322 		 * attribute for non-inclusive descendent `<option>` elements 
 1323 		 * depending on whether the value matches
 1324 		 * - `user-email-value-checked`: sets or unsets the `checked` 
 1325 		 * attribute depending on whether the value matches
 1326 		 * - `user-email-text`: replace contents with **email** data
 1327 		 * - `user-email-value`: replace `value` attribute with **email** 
 1328 		 * data
 1329 		 * - `user-has-image`: *hide* class removed if value is not null, 
 1330 		 * otherwise it is added
 1331 		 * - `user-no-image`: *hide* class added if value is not null, 
 1332 		 * otherwise it is removed
 1333 		 * - `user-image-enum-select`: sets or unsets the `selected` 
 1334 		 * attribute for non-inclusive descendent `<option>` elements 
 1335 		 * depending on whether the value matches (if non-null) (the 
 1336 		 * base64 encoded value)
 1337 		 * - `user-image-value-checked`: sets or unsets the `checked` 
 1338 		 * attribute depending on whether the value matches (if non-null) 
 1339 		 * (the base64 encoded value)
 1340 		 * - `user-image-text`: replace contents with **image** data (if 
 1341 		 * non-null) (the base64 encoded value)
 1342 		 * - `user-image-value`: replace `value` attribute with **image** 
 1343 		 * data (if non-null) (the base64 encoded value)
 1344 		 * - `user-name-enum-select`: sets or unsets the `selected` 
 1345 		 * attribute for non-inclusive descendent `<option>` elements 
 1346 		 * depending on whether the value matches
 1347 		 * - `user-name-value-checked`: sets or unsets the `checked` 
 1348 		 * attribute depending on whether the value matches
 1349 		 * - `user-name-text`: replace contents with **name** data
 1350 		 * - `user-name-value`: replace `value` attribute with **name** 
 1351 		 * data
 1352 		 * - `user-uid-enum-select`: sets or unsets the `selected` 
 1353 		 * attribute for non-inclusive descendent `<option>` elements 
 1354 		 * depending on whether the value matches
 1355 		 * - `user-uid-value-checked`: sets or unsets the `checked` 
 1356 		 * attribute depending on whether the value matches
 1357 		 * - `user-uid-text`: replace contents with **uid** data
 1358 		 * - `user-uid-value`: replace `value` attribute with **uid** 
 1359 		 * data
 1360 		 * 
 1361 		 * @param e The DOM element.
 1362 		 * @param custom The dictionary of functions keyed by structure 
 1363 		 * and field name (e.g., *foo** structure, **bar** field would be 
 1364 		 * `foo-bar`). The value is a function for custom handling that 
 1365 		 * accepts the 'e' value, the name of the structure-field, and 
 1366 		 * the value of the structure and field. You may also specify an 
 1367 		 * array of functions instead of a singleton. These callbacks are 
 1368 		 * invoked *after* the generic classes are filled.
 1369 		 */
 1370 		fill(e: HTMLElement|null, custom?: DataCallbacks|null): void
 1371 		{
 1372 			if (e !== null)
 1373 				this._fill(e, this.obj, true, custom);
 1374 		}
 1375 
 1376 		/**
 1377 		 * Like {@link fill} but not including the passed-in element.
 1378 		 * @param e The DOM element.
 1379 		 * @param custom Custom handler dictionary (see {@link fill} for 
 1380 		 * details).
 1381 		 */
 1382 		fillInner(e: HTMLElement|null, custom?: DataCallbacks|null): 
 1383 			void
 1384 		{
 1385 			if (e !== null)
 1386 				this._fill(e, this.obj, false, custom);
 1387 		}
 1388 
 1389 		/**
 1390 		 * Like {@link fill} but instead of accepting a single element to 
 1391 		 * fill, filling into all elements (inclusive) matching the given 
 1392 		 * class name beneath (inclusive) the element.
 1393 		 * @param e The DOM element.
 1394 		 * @param name Name of the class to fill.
 1395 		 * @param custom Custom handler dictionary (see {@link fill} for 
 1396 		 * details).
 1397 		 */
 1398 		fillByClass(e: HTMLElement|null, name: string, 
 1399 			custom?: DataCallbacks|null): void
 1400 		{
 1401 			if (e !== null)
 1402 				this._fillByClass(e, name, true, custom);
 1403 		}
 1404 
 1405 		/**
 1406 		 * Like {@link fillByClass} but not inclusive the root element 
 1407 		 * and class matches.
 1408 		 * @param e The DOM element.
 1409 		 * @param name Name of the class to fill.
 1410 		 * @param custom Custom handler dictionary (see {@link fill} for 
 1411 		 * details).
 1412 		 */
 1413 		fillInnerByClass(e: HTMLElement|null, name: string, 
 1414 			custom?: DataCallbacks|null): void
 1415 		{
 1416 			if (e !== null)
 1417 				this._fillByClass(e, name, false, custom);
 1418 		}
 1419 
 1420 		private _fill(e: HTMLElement, obj: userData|userData[], 
 1421 			inc: boolean, custom?: DataCallbacks|null): 
 1422 			void
 1423 		{
 1424 			if (Array.isArray(obj) && obj.length === 0)
 1425 				return;
 1426 			const o = Array.isArray(obj) ? obj[0] : obj;
 1427 			if (typeof(custom) === 'undefined')
 1428 				custom = null;
 1429 			_fillField(e, 'user', 'company', custom,
 1430 				o.company, inc, false,
 1431 				new company(o.company));
 1432 			_fillField(e, 'user', 'cid', custom, o.cid, inc,
 1433 				false,null);
 1434 			_fillField(e, 'user', 'sex', custom, o.sex, inc,
 1435 				false,null);
 1436 			_fillField(e, 'user', 'email', custom,
 1437 				o.email, inc, false,null);
 1438 			_fillField(e, 'user', 'image', custom,
 1439 				o.image, inc, true,null);
 1440 			_fillField(e, 'user', 'name', custom,
 1441 				o.name, inc, false,null);
 1442 			_fillField(e, 'user', 'uid', custom, o.uid, inc,
 1443 				false,null);
 1444 			if (custom !== null &&
 1445 			    typeof(custom['user']) !== 'undefined') {
 1446 				if (Array.isArray(custom['user'])) {
 1447 					for (const fn of custom['user'])
 1448 						fn(e, 'user', o);
 1449 				} else
 1450 					custom['user'](e, 'user', o);
 1451 			}
 1452 		}
 1453 
 1454 		private _fillByClass(e: HTMLElement, name: string, inc: boolean, 
 1455 			custom?: DataCallbacks|null): void
 1456 		{
 1457 			for (const elem of _elemList(e, name, inc))
 1458 				this._fill(elem, this.obj, inc, custom);
 1459 		}
 1460 
 1461 		/**
 1462 		 * Like {@link fillArray}, but hiding an element if the array is 
 1463 		 * empty or null.
 1464 		 * @param e The DOM element.
 1465 		 * @param tohide DOM element to hide.
 1466 		 * @param o The array (or object) to fill.
 1467 		 * @param custom Custom handler dictionary (see {@link fill}).
 1468 		 */
 1469 		fillArrayOrHide(e: HTMLElement|null, tohide: HTMLElement|null, 
 1470 			custom?: DataCallbacks|null): void
 1471 		{
 1472 			const len = (this.obj === null) ? 0 :
 1473 				Array.isArray(this.obj) ? this.obj.length :
 1474 				1;
 1475 			if (e !== null)
 1476 				_hide(e);
 1477 			if (tohide !== null)
 1478 				_show(tohide);
 1479 			this.fillArray(e, custom);
 1480 			if (tohide !== null && len === 0)
 1481 				_hide(tohide);
 1482 		}
 1483 
 1484 		/**
 1485 		 * Like {@link fillArray}, but showing an element if the array is 
 1486 		 * empty or null.
 1487 		 * @param e The DOM element.
 1488 		 * @param toshow The DOM element to show.
 1489 		 * @param o The array or object to fill.
 1490 		 * @param custom Custom handler dictionary (see {@link fill}).
 1491 		 */
 1492 		fillArrayOrShow(e: HTMLElement|null, toshow: HTMLElement|null, 
 1493 			custom?: DataCallbacks|null): void
 1494 		{
 1495 			const len = (this.obj === null) ? 0 :
 1496 				Array.isArray(this.obj) ? this.obj.length :
 1497 				1;
 1498 			if (e !== null)
 1499 				_hide(e);
 1500 			if (toshow !== null)
 1501 				_hide(toshow);
 1502 			this.fillArray(e, custom);
 1503 			if (toshow !== null && len === 0)
 1504 				_show(toshow);
 1505 		}
 1506 
 1507 		/**
 1508 		 * Like {@link fill} but for an array. If the data is not an 
 1509 		 * array, it is remapped as an array of one. This will save the 
 1510 		 * first element within 'e', remove all children of 'e', then 
 1511 		 * repeatedly clone the saved element and re-append it, filling 
 1512 		 * in the cloned subtree with the array (inclusive of the subtree 
 1513 		 * root). If the input array is empty or null, 'e' is hidden by 
 1514 		 * using the *hide* class. Otherwise, the *hide* class is 
 1515 		 * removed.
 1516 		 * @param e The DOM element.
 1517 		 * @param custom Custom handler dictionary (see {@link fill}).
 1518 		 */
 1519 		fillArray(e: HTMLElement|null, custom?: DataCallbacks|null): 
 1520 			void
 1521 		{
 1522 			const o = Array.isArray(this.obj) ?
 1523 				this.obj : [this.obj];
 1524 			if (e === null || e.children.length === 0)
 1525 				return;
 1526 			_hide(e);
 1527 			if (o.length === 0 || this.obj === null)
 1528 				return;
 1529 			_show(e);
 1530 			const row = e.children[0];
 1531 			e.replaceChildren();
 1532 			for (const obj of o) {
 1533 				const cln = <HTMLElement>row.cloneNode(true);
 1534 				e.append(cln);
 1535 				this._fill(cln, obj, true, custom);
 1536 			}
 1537 		}
 1538 
 1539 		/**
 1540 		 * Like {@link fillArray} but instead of accepting a single 
 1541 		 * element to fill, filling all elements by class name beneath 
 1542 		 * the given root (non-inclusive).
 1543 		 * @param e The DOM element.
 1544 		 * @param name Name of the class to fill.
 1545 		 * @param custom Custom handler dictionary (see {@link fill} for 
 1546 		 * details).
 1547 		 */
 1548 		fillArrayByClass(e: HTMLElement|null, name: string, 
 1549 			custom?: DataCallbacks|null): void
 1550 		{
 1551 			for (const elem of _elemList(e, name, false))
 1552 				this.fillArray(elem, custom);
 1553 		}
 1554 
 1555 	}
 1556 
 1557 	/**
 1558 	 * Writes {@link sessionData} into a DOM tree.
 1559 	 */
 1560 	export class session {
 1561 		readonly obj: sessionData|sessionData[];
 1562 		/**
 1563 		 * @param obj The object(s) to write.
 1564 		 */
 1565 		constructor(o: sessionData|sessionData[])
 1566 		{
 1567 			this.obj = o;
 1568 		}
 1569 
 1570 		/**
 1571 		 * Writes {@link sessionData} into the given element. If 
 1572 		 * constructed with an array, the first element is used.  
 1573 		 * Elements within (and including) the element having the 
 1574 		 * following classes are manipulated as follows:
 1575 		 * 
 1576 		 * - `session-user-obj`: invoke {@link user#fillInner} with 
 1577 		 * **user** data
 1578 		 * - `session-userid-enum-select`: sets or unsets the `selected` 
 1579 		 * attribute for non-inclusive descendent `<option>` elements 
 1580 		 * depending on whether the value matches
 1581 		 * - `session-userid-value-checked`: sets or unsets the `checked` 
 1582 		 * attribute depending on whether the value matches
 1583 		 * - `session-userid-text`: replace contents with **userid** data
 1584 		 * - `session-userid-value`: replace `value` attribute with 
 1585 		 * **userid** data
 1586 		 * - `session-token-enum-select`: sets or unsets the `selected` 
 1587 		 * attribute for non-inclusive descendent `<option>` elements 
 1588 		 * depending on whether the value matches
 1589 		 * - `session-token-value-checked`: sets or unsets the `checked` 
 1590 		 * attribute depending on whether the value matches
 1591 		 * - `session-token-text`: replace contents with **token** data
 1592 		 * - `session-token-value`: replace `value` attribute with 
 1593 		 * **token** data
 1594 		 * - `session-mtime-enum-select`: sets or unsets the `selected` 
 1595 		 * attribute for non-inclusive descendent `<option>` elements 
 1596 		 * depending on whether the value matches
 1597 		 * - `session-mtime-value-checked`: sets or unsets the `checked` 
 1598 		 * attribute depending on whether the value matches
 1599 		 * - `session-mtime-text`: replace contents with **mtime** data
 1600 		 * - `session-mtime-value`: replace `value` attribute with 
 1601 		 * **mtime** data
 1602 		 * - `session-mtime-date-value`: set the element's `value` to the 
 1603 		 * ISO-8601 date format of the data
 1604 		 * - `session-mtime-date-text`: like `session-mtime-date-value`, 
 1605 		 * but replacing textual content
 1606 		 * - `session-id-enum-select`: sets or unsets the `selected` 
 1607 		 * attribute for non-inclusive descendent `<option>` elements 
 1608 		 * depending on whether the value matches
 1609 		 * - `session-id-value-checked`: sets or unsets the `checked` 
 1610 		 * attribute depending on whether the value matches
 1611 		 * - `session-id-text`: replace contents with **id** data
 1612 		 * - `session-id-value`: replace `value` attribute with **id** 
 1613 		 * data
 1614 		 * 
 1615 		 * @param e The DOM element.
 1616 		 * @param custom The dictionary of functions keyed by structure 
 1617 		 * and field name (e.g., *foo** structure, **bar** field would be 
 1618 		 * `foo-bar`). The value is a function for custom handling that 
 1619 		 * accepts the 'e' value, the name of the structure-field, and 
 1620 		 * the value of the structure and field. You may also specify an 
 1621 		 * array of functions instead of a singleton. These callbacks are 
 1622 		 * invoked *after* the generic classes are filled.
 1623 		 */
 1624 		fill(e: HTMLElement|null, custom?: DataCallbacks|null): void
 1625 		{
 1626 			if (e !== null)
 1627 				this._fill(e, this.obj, true, custom);
 1628 		}
 1629 
 1630 		/**
 1631 		 * Like {@link fill} but not including the passed-in element.
 1632 		 * @param e The DOM element.
 1633 		 * @param custom Custom handler dictionary (see {@link fill} for 
 1634 		 * details).
 1635 		 */
 1636 		fillInner(e: HTMLElement|null, custom?: DataCallbacks|null): 
 1637 			void
 1638 		{
 1639 			if (e !== null)
 1640 				this._fill(e, this.obj, false, custom);
 1641 		}
 1642 
 1643 		/**
 1644 		 * Like {@link fill} but instead of accepting a single element to 
 1645 		 * fill, filling into all elements (inclusive) matching the given 
 1646 		 * class name beneath (inclusive) the element.
 1647 		 * @param e The DOM element.
 1648 		 * @param name Name of the class to fill.
 1649 		 * @param custom Custom handler dictionary (see {@link fill} for 
 1650 		 * details).
 1651 		 */
 1652 		fillByClass(e: HTMLElement|null, name: string, 
 1653 			custom?: DataCallbacks|null): void
 1654 		{
 1655 			if (e !== null)
 1656 				this._fillByClass(e, name, true, custom);
 1657 		}
 1658 
 1659 		/**
 1660 		 * Like {@link fillByClass} but not inclusive the root element 
 1661 		 * and class matches.
 1662 		 * @param e The DOM element.
 1663 		 * @param name Name of the class to fill.
 1664 		 * @param custom Custom handler dictionary (see {@link fill} for 
 1665 		 * details).
 1666 		 */
 1667 		fillInnerByClass(e: HTMLElement|null, name: string, 
 1668 			custom?: DataCallbacks|null): void
 1669 		{
 1670 			if (e !== null)
 1671 				this._fillByClass(e, name, false, custom);
 1672 		}
 1673 
 1674 		private _fill(e: HTMLElement, obj: sessionData|sessionData[], 
 1675 			inc: boolean, custom?: DataCallbacks|null): 
 1676 			void
 1677 		{
 1678 			if (Array.isArray(obj) && obj.length === 0)
 1679 				return;
 1680 			const o = Array.isArray(obj) ? obj[0] : obj;
 1681 			if (typeof(custom) === 'undefined')
 1682 				custom = null;
 1683 			_fillField(e, 'session', 'user', custom,
 1684 				o.user, inc, false,
 1685 				new user(o.user));
 1686 			_fillField(e, 'session', 'userid', custom,
 1687 				o.userid, inc, false,null);
 1688 			_fillField(e, 'session', 'token', custom,
 1689 				o.token, inc, false,null);
 1690 			_fillField(e, 'session', 'mtime', custom,
 1691 				o.mtime, inc, false,null);
 1692 			_fillDateValue(e, 'session-mtime', o.mtime, inc);
 1693 			_fillField(e, 'session', 'id', custom, o.id, inc,
 1694 				false,null);
 1695 			if (custom !== null &&
 1696 			    typeof(custom['session']) !== 'undefined') {
 1697 				if (Array.isArray(custom['session'])) {
 1698 					for (const fn of custom['session'])
 1699 						fn(e, 'session', o);
 1700 				} else
 1701 					custom['session'](e, 'session', o);
 1702 			}
 1703 		}
 1704 
 1705 		private _fillByClass(e: HTMLElement, name: string, inc: boolean, 
 1706 			custom?: DataCallbacks|null): void
 1707 		{
 1708 			for (const elem of _elemList(e, name, inc))
 1709 				this._fill(elem, this.obj, inc, custom);
 1710 		}
 1711 
 1712 		/**
 1713 		 * Like {@link fillArray}, but hiding an element if the array is 
 1714 		 * empty or null.
 1715 		 * @param e The DOM element.
 1716 		 * @param tohide DOM element to hide.
 1717 		 * @param o The array (or object) to fill.
 1718 		 * @param custom Custom handler dictionary (see {@link fill}).
 1719 		 */
 1720 		fillArrayOrHide(e: HTMLElement|null, tohide: HTMLElement|null, 
 1721 			custom?: DataCallbacks|null): void
 1722 		{
 1723 			const len = (this.obj === null) ? 0 :
 1724 				Array.isArray(this.obj) ? this.obj.length :
 1725 				1;
 1726 			if (e !== null)
 1727 				_hide(e);
 1728 			if (tohide !== null)
 1729 				_show(tohide);
 1730 			this.fillArray(e, custom);
 1731 			if (tohide !== null && len === 0)
 1732 				_hide(tohide);
 1733 		}
 1734 
 1735 		/**
 1736 		 * Like {@link fillArray}, but showing an element if the array is 
 1737 		 * empty or null.
 1738 		 * @param e The DOM element.
 1739 		 * @param toshow The DOM element to show.
 1740 		 * @param o The array or object to fill.
 1741 		 * @param custom Custom handler dictionary (see {@link fill}).
 1742 		 */
 1743 		fillArrayOrShow(e: HTMLElement|null, toshow: HTMLElement|null, 
 1744 			custom?: DataCallbacks|null): void
 1745 		{
 1746 			const len = (this.obj === null) ? 0 :
 1747 				Array.isArray(this.obj) ? this.obj.length :
 1748 				1;
 1749 			if (e !== null)
 1750 				_hide(e);
 1751 			if (toshow !== null)
 1752 				_hide(toshow);
 1753 			this.fillArray(e, custom);
 1754 			if (toshow !== null && len === 0)
 1755 				_show(toshow);
 1756 		}
 1757 
 1758 		/**
 1759 		 * Like {@link fill} but for an array. If the data is not an 
 1760 		 * array, it is remapped as an array of one. This will save the 
 1761 		 * first element within 'e', remove all children of 'e', then 
 1762 		 * repeatedly clone the saved element and re-append it, filling 
 1763 		 * in the cloned subtree with the array (inclusive of the subtree 
 1764 		 * root). If the input array is empty or null, 'e' is hidden by 
 1765 		 * using the *hide* class. Otherwise, the *hide* class is 
 1766 		 * removed.
 1767 		 * @param e The DOM element.
 1768 		 * @param custom Custom handler dictionary (see {@link fill}).
 1769 		 */
 1770 		fillArray(e: HTMLElement|null, custom?: DataCallbacks|null): 
 1771 			void
 1772 		{
 1773 			const o = Array.isArray(this.obj) ?
 1774 				this.obj : [this.obj];
 1775 			if (e === null || e.children.length === 0)
 1776 				return;
 1777 			_hide(e);
 1778 			if (o.length === 0 || this.obj === null)
 1779 				return;
 1780 			_show(e);
 1781 			const row = e.children[0];
 1782 			e.replaceChildren();
 1783 			for (const obj of o) {
 1784 				const cln = <HTMLElement>row.cloneNode(true);
 1785 				e.append(cln);
 1786 				this._fill(cln, obj, true, custom);
 1787 			}
 1788 		}
 1789 
 1790 		/**
 1791 		 * Like {@link fillArray} but instead of accepting a single 
 1792 		 * element to fill, filling all elements by class name beneath 
 1793 		 * the given root (non-inclusive).
 1794 		 * @param e The DOM element.
 1795 		 * @param name Name of the class to fill.
 1796 		 * @param custom Custom handler dictionary (see {@link fill} for 
 1797 		 * details).
 1798 		 */
 1799 		fillArrayByClass(e: HTMLElement|null, name: string, 
 1800 			custom?: DataCallbacks|null): void
 1801 		{
 1802 			for (const elem of _elemList(e, name, false))
 1803 				this.fillArray(elem, custom);
 1804 		}
 1805 
 1806 	}
 1807 
 1808 	/**
 1809 	 * Birthsex of individual
 1810 	 */
 1811 	export class sex {
 1812 		/**
 1813 		 * Male
 1814 		 */
 1815 		static readonly male = '0';
 1816 		/**
 1817 		 * Female
 1818 		 */
 1819 		static readonly female = '1';
 1820 		/**
 1821 		 * Other
 1822 		 */
 1823 		static readonly other = '2';
 1824 		/**
 1825 		 * Uses the enumeration item's **jslabel** (or an empty string if 
 1826 		 * no **jslabel** is defined or there is no matching item for the 
 1827 		 * value) to format a custom label. This will act on 
 1828 		 * *xxx-yyy-label* classes, where *xxx* is the structure name and 
 1829 		 * *yyy* is the field name.
 1830 		 * A null value is represented by the **isnull** labels (the 
 1831 		 * `ort-null` class is also appended in this case)
 1832 		 * @param e The DOM element.
 1833 		 * @param name If non-null, data is written to elements under the 
 1834 		 * root with the given class name. If null, data is written 
 1835 		 * directly into the DOM element.
 1836 		 * @param v The enumeration value.
 1837 		 */
 1838 		static format(e: HTMLElement, name: string|null, 
 1839 			v: string|number|null): void
 1840 		{
 1841 			let s: string;
 1842 			if (name !== null)
 1843 				name += '-label';
 1844 			if (v === null && name !== null) {
 1845 				_classaddcl(e, name, 'ort-null', false);
 1846 				_replcllang(e, name, {_default: ''});
 1847 				return;
 1848 			} else if (v === null) {
 1849 				_classadd(e, 'ort-null');
 1850 				_repllang(e, {_default: ''});
 1851 				return;
 1852 			}
 1853 			switch(v.toString()) {
 1854 			case sex.male:
 1855 				s = _strlang({_default: 'male'});
 1856 				break;
 1857 			case sex.female:
 1858 				s = _strlang({_default: 'female'});
 1859 				break;
 1860 			case sex.other:
 1861 				s = _strlang({_default: 'other'});
 1862 				break;
 1863 			default:
 1864 				s = '';
 1865 				break;
 1866 			}
 1867 			if (name !== null)
 1868 				_replcl(e, name, s, false);
 1869 			else
 1870 				_repl(e, s);
 1871 		}
 1872 	}
 1873 
 1874 }