var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
/*
This file is part of »bacterio-plankton:base«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:base« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:base« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:base«. If not, see <http://www.gnu.org/licenses/>.
 */
// }
/*
This file is part of »bacterio-plankton:base«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:base« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:base« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:base«. If not, see <http://www.gnu.org/licenses/>.
 */
;
var lib_plankton;
(function (lib_plankton) {
    var base;
    (function (base) {
        /**
         * @author fenris
         */
        function environment() {
            return "node";
        }
        base.environment = environment;
    })(base = lib_plankton.base || (lib_plankton.base = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:base«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:base« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:base« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:base«. If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * @author fenris
 */
/*export*/ function pseudopointer_null() {
    return {
        "value": null
    };
}
/**
 * @author fenris
 */
/*export*/ function pseudopointer_make(value) {
    return {
        "value": value
    };
}
/**
 * @author fenris
 */
/*export*/ function pseudopointer_isset(pseudopointer) {
    return (pseudopointer.value != null);
}
/**
 * @author fenris
 */
/*export*/ function pseudopointer_read(pseudopointer) {
    if (pseudopointer.value != null) {
        return pseudopointer.value;
    }
    else {
        var message = "nullpointer dereferencation";
        throw (new Error(message));
    }
}
/**
 * @author fenris
 */
/*export*/ function pseudopointer_write(pseudopointer, value) {
    pseudopointer.value = value;
}
/*
This file is part of »bacterio-plankton:base«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:base« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:base« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:base«. If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * @author fenris
 */
var instance_verbosity = 0;
/**
 * @author fenris
 */
function instance_collate(value1, value2) {
    if (typeof (value1) === "object") {
        if (value1 == null) {
            return (value2 == null);
        }
        else {
            if ("_collate" in value1) {
                return value1["_collate"](value2);
            }
            else {
                throw (new Error("[collate]" + " " + "object has no such method"));
            }
        }
    }
    else {
        if (instance_verbosity >= 1) {
            // lib_plankton.log.warn("[collate]" + " " + "primitive value; using default implementation");
        }
        return (value1 === value2);
    }
}
/**
 * @author fenris
 */
function instance_compare(value1, value2) {
    if (typeof (value1) === "object") {
        if ("_compare" in value1) {
            return value1["_compare"](value2);
        }
        else {
            throw (new Error("[compare]" + " " + "object has no such method"));
        }
    }
    else {
        if (instance_verbosity >= 1) {
            // lib_plankton.log.warn("[compare]" + " " + "primitive value; using default implementation");
        }
        return (value1 <= value2);
    }
}
/**
 * @author fenris
 */
function instance_clone(value) {
    if (typeof (value) === "object") {
        if ("_clone" in value) {
            return value["_clone"]();
        }
        else {
            throw (new Error("[clone]" + " " + "object has no such method"));
        }
    }
    else {
        if (instance_verbosity >= 1) {
            // lib_plankton.log.warn("[clone]" + " " + "primitive value; using default implementation");
        }
        return value;
    }
}
/**
 * @desc the ability to generate a string out of the element, which identifies it to a high degree
 * @author fenris
 */
function instance_hash(value) {
    if (typeof (value) === "object") {
        if ("_hash" in value) {
            return value["_hash"]();
        }
        else {
            throw (new Error("[hash]" + " " + "object has no such method"));
        }
    }
    else {
        if (instance_verbosity >= 1) {
            // lib_plankton.log.warn("[hash]" + " " + "primitive value; using default implementation");
        }
        return String(value);
    }
}
/**
 * @desc the ability to map the element to a textual representation (most likely not injective)
 * @author fenris
 */
function instance_show(value) {
    if (typeof (value) === "object") {
        if (value == null) {
            return "NULL";
        }
        else {
            if ("_show" in value) {
                return value["_show"]();
            }
            else {
                // throw (new Error("[show]" + " " + "object has no such method"));
                return JSON.stringify(value);
            }
        }
    }
    else {
        if (instance_verbosity >= 1) {
            // lib_plankton.log.warn("[show]" + " " + "primitive value; using default implementation");
        }
        return String(value);
    }
}
/*
This file is part of »bacterio-plankton:base«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:base« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:base« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:base«. If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * @author frac
 */
var class_observer = /** @class */ (function () {
    /**
     * @author frac
     */
    function class_observer() {
        this.counter = 0;
        this.actions = {};
        this.buffer = [];
    }
    /**
     * @author frac
     */
    class_observer.prototype.empty = function () {
        return (Object.keys(this.actions).length == 0);
    };
    /**
     * @author frac
     */
    class_observer.prototype.flush = function () {
        this.actions = {};
    };
    /**
     * @author frac
     */
    class_observer.prototype.set = function (id, action) {
        this.actions[id] = action;
    };
    /**
     * @author frac
     */
    class_observer.prototype.del = function (id) {
        delete this.actions[id];
    };
    /**
     * @author frac
     */
    class_observer.prototype.add = function (action) {
        this.set((this.counter++).toString(), action);
    };
    /**
     * @author frac
     */
    class_observer.prototype.notify = function (information, delayed) {
        var _this = this;
        if (information === void 0) { information = {}; }
        if (delayed === void 0) { delayed = false; }
        if (delayed) {
            this.buffer.push(information);
        }
        else {
            Object.keys(this.actions).forEach(function (id) { return _this.actions[id](information); });
        }
    };
    /**
     * @author frac
     */
    class_observer.prototype.rollout = function () {
        var _this = this;
        this.buffer.forEach(function (information) { return _this.notify(information, false); });
        this.buffer = [];
    };
    return class_observer;
}());
/**
 * @author frac
 */
/*
export interface interface_readable<type_value> {

    |**
     * @author frac
     *|
    read() : type_executor<type_value, Error>;

}
 */
/**
 * @author frac
 */
/*
export interface interface_writeable<type_value> {

    |**
     * @author frac
     *|
    write(value : type_value) : type_executor<void, Error>;

}
 */
/*
This file is part of »bacterio-plankton:base«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:base« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:base« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:base«. If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * @author frac
 */
var class_error = /** @class */ (function (_super) {
    __extends(class_error, _super);
    /**
     * @author frac
     */
    function class_error(message, suberrors) {
        if (suberrors === void 0) { suberrors = []; }
        var _this = _super.call(this, message) || this;
        _this.suberrors = suberrors;
        _this.mess = message;
        return _this;
    }
    /**
     * @override
     * @author frac
     */
    class_error.prototype.toString = function () {
        return ( /*super.toString()*/this.mess + " " + ("[" + this.suberrors.map(function (x) { return x.toString(); }).join(",") + "]"));
    };
    return class_error;
}(Error));
var lib_plankton;
(function (lib_plankton) {
    var base;
    (function (base) {
        /**
         * returns the current UNIX timestamp
         *
         * @author fenris
         */
        function get_current_timestamp(rounded) {
            if (rounded === void 0) { rounded = false; }
            var x = (Date.now() / 1000);
            return (rounded ? Math.round(x) : x);
            ;
        }
        base.get_current_timestamp = get_current_timestamp;
        /**
         */
        function object_merge(core, mantle) {
            return Object.assign(core, mantle);
        }
        base.object_merge = object_merge;
    })(base = lib_plankton.base || (lib_plankton.base = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:pod«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:pod« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:pod« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:pod«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var pod;
    (function (pod_1) {
        /**
         * @author fenris
         */
        function make_empty() {
            return {
                "kind": "empty"
            };
        }
        pod_1.make_empty = make_empty;
        /**
         * @author fenris
         */
        function make_filled(value) {
            return {
                "kind": "filled",
                "value": value
            };
        }
        pod_1.make_filled = make_filled;
        /**
         * whether the pod is filled
         *
         * @author fenris
         */
        function is_filled(pod) {
            return (pod.kind === "filled");
        }
        pod_1.is_filled = is_filled;
        /**
         * return the value, stored in the pod-wrapper
         *
         * @author fenris
         */
        function cull(pod) {
            if (!is_filled(pod)) {
                throw (new Error("cull from empty"));
            }
            else {
                return pod.value;
            }
        }
        pod_1.cull = cull;
        /**
         * to pass on a empty-pod or to use a filled-pod
         *
         * @author fenris
         */
        function propagate(pod, function_) {
            if (!is_filled(pod)) {
                return make_empty();
            }
            else {
                return make_filled(function_(pod.value));
            }
        }
        pod_1.propagate = propagate;
        /**
         * @author fenris
         */
        function distinguish(pod, function_empty, function_filled) {
            return ((!is_filled(pod))
                ? function_empty()
                : function_filled(pod.value));
        }
        pod_1.distinguish = distinguish;
        /**
         */
        function show(pod, options = {}) {
            options = Object.assign({
                "show_value": value => String(value),
            }, options);
            if (!is_filled(pod)) {
                return "<·>";
            }
            else {
                return ("<- " + options.show_value(pod.value) + " ->");
            }
        }
        pod_1.show = show;
    })(pod = lib_plankton.pod || (lib_plankton.pod = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:pod«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:pod« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:pod« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:pod«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var pod;
    (function (pod) {
        /**
         */
        class class_pod {
            constructor(subject) { this.subject = subject; }
            is_empty() { return (!pod.is_filled(this.subject)); }
            is_filled() { return pod.is_filled(this.subject); }
            cull() { return pod.cull(this.subject); }
            show(show_value = undefined) { return pod.show(this.subject, show_value); }
            toString() { return this.show(); }
            propagate(function_) { return new class_pod(pod.propagate(this.subject, function_)); }
            distinguish(function_empty, function_filled) { return pod.distinguish(this.subject, function_empty, function_filled); }
        }
        pod.class_pod = class_pod;
    })(pod = lib_plankton.pod || (lib_plankton.pod = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:call«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:call« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:call« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:call«. If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * might be completely obsolete
 */
var lib_plankton;
(function (lib_plankton) {
    var call;
    (function (call) {
        /**
         * @author fenris
         */
        function promise_reject(reason) {
            return Promise.reject(reason);
        }
        call.promise_reject = promise_reject;
        /**
         * @author fenris
         */
        function promise_resolve(result) {
            return Promise.resolve(result);
        }
        call.promise_resolve = promise_resolve;
        /**
         * @author fenris
         */
        function promise_make(executor) {
            return (new Promise(executor));
        }
        call.promise_make = promise_make;
        /**
         * @author fenris
         */
        function promise_then_close(promise, resolver, rejector) {
            promise.then(resolver, rejector);
        }
        call.promise_then_close = promise_then_close;
        /**
         * @author fenris
         */
        function promise_then_append(promise, resolver, rejector = null) {
            if (rejector == null) {
                rejector = (reason) => promise_reject(reason);
            }
            return (promise.then(resolver, rejector));
        }
        call.promise_then_append = promise_then_append;
        /**
         * @author fenris
         */
        function promise_all(promises) {
            return Promise.all(promises);
        }
        call.promise_all = promise_all;
        /**
         * @author fenris
         */
        function promise_chain(promises, start = undefined) {
            return (promises.reduce((chain, promise) => promise_then_append(chain, promise), promise_resolve(start)));
        }
        call.promise_chain = promise_chain;
        /**
         * @author fenris
         */
        function promise_condense(promises) {
            return (promise_chain(promises.map(promise => result => promise_then_append(promise(), element => promise_resolve(result.concat([element])))), []));
        }
        call.promise_condense = promise_condense;
        /**
         * @author fenris
         */
        function promise_group(promises, options = {
            "serial": false,
        }) {
            const decorate = function (promise, name) {
                return (() => promise_then_append(promise(), value => promise_resolve({ "key": name, "value": value })));
            };
            if (options.serial) {
                return (promise_then_append(promise_condense(Object.keys(promises)
                    .map(name => decorate(promises[name], name))), list => promise_resolve(Object.fromEntries(list.map(({ "key": key, "value": value }) => ([key, value]))))));
            }
            else {
                return (promise_then_append(promise_all(Object.keys(promises)
                    .map(name => decorate(promises[name], name))
                    .map(promise => promise())), list => promise_resolve(Object.fromEntries(list.map(({ "key": key, "value": value }) => ([key, value]))))));
            }
        }
        call.promise_group = promise_group;
        /**
         * @author fenris
         */
        function promise_wrap(promise, transformator_result, transformator_reason = lib_plankton.call.id) {
            return (promise_make((resolve, reject) => {
                promise_then_close(promise, result => resolve(transformator_result(result)), reason => reject(transformator_reason(reason)));
            }));
        }
        call.promise_wrap = promise_wrap;
        /**
         * @author fenris
         */
        /*
        export function promise_show<type_result, type_reason>(label : string) : (result : type_result)=>type_promise<type_result, type_reason> {
            return (
                result => promise_make<type_result, type_reason>(
                    (resolve, reject) => {
                        // lib_plankton.log.info(label + ": " + instance_show(result));
                        process.stdout.write(label + ": " + instance_show(result));
                        resolve(result);
                    }
                )
            );
        }
         */
        /**
         * @author fenris
         */
        /*
        export function promise_log<type_result, type_reason>(result : type_result) : (result : type_result)=>type_promise<type_result, type_reason> {
            return promise_show<type_result, type_reason>("log");
        }
         */
        /**
         * @author fenris
         */
        function promise_attach(state, promise, name) {
            return (promise_wrap(promise, result => {
                state[name] = result;
                return state;
            }));
        }
        call.promise_attach = promise_attach;
        /**
         * @author fenris
         */
        function promise_delay(promise, delay) {
            return promise_make((resolve, reject) => {
                call.timeout(() => {
                    promise_then_close(promise, resolve, reject);
                    return null;
                }, delay);
            });
        }
        call.promise_delay = promise_delay;
    })(call = lib_plankton.call || (lib_plankton.call = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:call«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:call« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:call« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:call«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var call;
    (function (call) {
        /**
         */
        class CancellablePromise extends Promise {
            /**
             */
            constructor(executor) {
                super((resolve, reject) => { });
                this.subject = (new Promise((resolve, reject) => {
                    Promise.race([
                        new Promise(executor),
                        new Promise((resolve_, reject_) => {
                            this.interval = setInterval(() => {
                                if (!this.cancelled) {
                                    // do nothing
                                }
                                else {
                                    reject_(new Error("cancelled"));
                                    this.clear();
                                }
                            }, 0);
                        }),
                    ])
                        .then(resolve, reject);
                }));
                this.cancelled = false;
                this.interval = null;
            }
            /**
             */
            clear() {
                if (this.interval === null) {
                    // do nothing
                }
                else {
                    clearInterval(this.interval);
                    this.interval = null;
                }
            }
            /**
             */
            then(onfulfilled, onrejected) {
                this.clear();
                return this.subject.then(onfulfilled, onrejected);
            }
            /**
             */
            catch(x) {
                this.clear();
                return this.subject.catch(x);
            }
            /**
             */
            cancel() {
                this.cancelled = true;
                this.clear();
            }
        }
        call.CancellablePromise = CancellablePromise;
    })(call = lib_plankton.call || (lib_plankton.call = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:call«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:call« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:call« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:call«. If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * initializer might be obsolete, since promises are reusable after having been resolved or rejected
 */
var lib_plankton;
(function (lib_plankton) {
    var call;
    (function (call) {
        /**
         * @author fenris
         */
        let enum_initializer_state;
        (function (enum_initializer_state) {
            enum_initializer_state[enum_initializer_state["initial"] = 0] = "initial";
            enum_initializer_state[enum_initializer_state["waiting"] = 1] = "waiting";
            enum_initializer_state[enum_initializer_state["successful"] = 2] = "successful";
            enum_initializer_state[enum_initializer_state["failed"] = 3] = "failed";
        })(enum_initializer_state = call.enum_initializer_state || (call.enum_initializer_state = {}));
        /**
         * @author fenris
         */
        function initializer_make(fetcher) {
            let subject = {
                "fetcher": fetcher,
                "state": enum_initializer_state.initial,
                "queue": [],
                "result": undefined,
                "reason": undefined,
            };
            return subject;
        }
        call.initializer_make = initializer_make;
        /**
         * @author fenris
         */
        function initializer_actuate(subject) {
            switch (subject.state) {
                case enum_initializer_state.successful: {
                    subject.queue.forEach(entry => entry.resolve(subject.result));
                    break;
                }
                case enum_initializer_state.failed: {
                    subject.queue.forEach(entry => entry.reject(subject.reason));
                    break;
                }
                default: {
                    throw (new Error(`unhandled state ${subject.state}`));
                    break;
                }
            }
        }
        /**
         * @author fenris
         */
        function initializer_reset(subject) {
            subject.state = enum_initializer_state.initial;
            subject.queue = [];
        }
        call.initializer_reset = initializer_reset;
        /**
         * @author fenris
         */
        function initializer_state(subject) {
            return subject.state;
        }
        call.initializer_state = initializer_state;
        /**
         * @author fenris
         */
        function initializer_get(subject) {
            switch (subject.state) {
                case enum_initializer_state.initial: {
                    subject.state = enum_initializer_state.waiting;
                    return (call.promise_make((resolve, reject) => {
                        subject.queue.push({ "resolve": resolve, "reject": reject });
                        subject.fetcher().then(result => {
                            subject.state = enum_initializer_state.successful;
                            subject.result = result;
                            initializer_actuate(subject);
                        }, reason => {
                            subject.state = enum_initializer_state.failed;
                            subject.reason = reason;
                            initializer_actuate(subject);
                        });
                    }));
                    break;
                }
                case enum_initializer_state.waiting: {
                    return (call.promise_make((resolve, reject) => {
                        subject.queue.push({ "resolve": resolve, "reject": reject });
                    }));
                    break;
                }
                case enum_initializer_state.successful: {
                    return (call.promise_resolve(subject.result));
                    break;
                }
                case enum_initializer_state.failed: {
                    return (call.promise_reject(subject.reason));
                    break;
                }
                default: {
                    throw (new Error(`unhandled state ${subject.state}`));
                    break;
                }
            }
        }
        call.initializer_get = initializer_get;
        /**
         * @author fenris
         */
        function initializer_get_sync(subject) {
            switch (subject.state) {
                case enum_initializer_state.successful: {
                    return subject.result;
                    break;
                }
                case enum_initializer_state.failed: {
                    throw subject.reason;
                    break;
                }
                default: {
                    throw (new Error(`unhandled state ${subject.state}`));
                    break;
                }
            }
        }
        /**
         * @author fenris
         */
        function initializer_set_sync(subject, result) {
            switch (subject.state) {
                case enum_initializer_state.successful: {
                    subject.result = result;
                    break;
                }
                case enum_initializer_state.failed: {
                    subject.state = enum_initializer_state.successful;
                    subject.result = result;
                    break;
                }
                default: {
                    throw (new Error(`unhandled state ${subject.state}`));
                    break;
                }
            }
        }
    })(call = lib_plankton.call || (lib_plankton.call = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:call«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:call« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:call« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:call«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var call;
    (function (call) {
        /*
            The core idea of this library is to provide means for asynchronous program flow. The old-school way to do is,
            is to use callbacks. While this approach is simple and easy to understand, it has some disadvantages. As an
            attempt to relief and improve this, the promise-system was introduced. In principle it solves most of the
            problems found in the callback-approach; however it has some downsides as well:
                
            - Convolution of multiple principles
                Promises unite the ideas of asynchronous program flow and error handling.
            
            - Instant execution
                Creating a promise results in the instant execution of the given executor prodecure. While this might be
                convenient in some cases, it can be quite disturbing and counter-intuitive in others.
            
            - Broken typing
                The Promise system doesn't distinguish between an appending "then" (i.e. passing a function, which returns a
                new promise) and a closing "then" (i.e. passing a function, which has no return value). On top of that it
                allows returning simple values in an appending "then", which results in an implicit call of the executors
                "resolve"-function. The price for these "pragmatic" features is that the whole system can't be typed well.
                And even though JavaScript is not a strictly typed language, it was a quite questionable decision to design
                the promise system in a way, which breaks typing from the start.
            
            The deferral-system forseeks to solve these issues while retaining the advantages of the promise-system.
         */
        /**
         * @author fenris
         * @desc activates the deferral and handles its output according to a given procedure
         * @param {(value : type_value)=>void} procedure a function which receives the output of the deferral as argument
         */
        function deferral_use(deferral, input, procedure) {
            deferral.representation(input).then(value => {
                procedure(value);
            }, reason => {
                throw reason;
            });
        }
        call.deferral_use = deferral_use;
        /**
         * @author fenris
         * @desc creates a deferral-subject (similar to "new Promise", where "convey" reflects "resolve"/"reject")
         */
        function deferral_make(handler) {
            return ({
                "representation": ((input) => (new Promise((resolve, reject) => {
                    handler(input, resolve);
                })))
            });
        }
        call.deferral_make = deferral_make;
        /**
         * @author fenris
         * @desc wraps a simple function into a deferral (similar to "Promise.resolve"/"Promise.reject")
         */
        function deferral_wrap(function_) {
            return (deferral_make((input, convey) => convey(function_(input))));
        }
        call.deferral_wrap = deferral_wrap;
        /**
         * @author fenris
         */
        function deferral_id() {
            return (deferral_make((input, convey) => convey(input)));
        }
        call.deferral_id = deferral_id;
        /**
         * @author fenris
         */
        function deferral_const(value) {
            return (deferral_make((input, convey) => convey(value)));
        }
        call.deferral_const = deferral_const;
        /**
         * @author fenris
         */
        function deferral_delay(output, delay) {
            return (deferral_make((input, convey) => {
                setTimeout(() => convey(output), delay);
            }));
        }
        call.deferral_delay = deferral_delay;
        /**
         * @author fenris
         * @desc connects two deferrals to form a new one; the output of the first is taken as input for the second
         *     (similar to "Promise.then" when passing a function which returns a new promise)
         * @param {type_deferral<type_value1>} first a simple deferral
         * @param {(value1 : type_value1)=>type_deferral<type_value2>} second a function depending from a value returning a deferral
         */
        function deferral_compose_serial(first, second) {
            return {
                "representation": ((input) => first.representation(input).then((between) => second.representation(between)))
            };
        }
        call.deferral_compose_serial = deferral_compose_serial;
        /**
         * @author fenris
         */
        function deferral_compose_parallel({ "left": deferral_left, "right": deferral_right, }) {
            return (deferral_make((input, convey) => {
                let object = {
                    "left": lib_plankton.pod.make_empty(),
                    "right": lib_plankton.pod.make_empty(),
                };
                let finish = function () {
                    if (lib_plankton.pod.is_filled(object.left)
                        &&
                            lib_plankton.pod.is_filled(object.right)) {
                        let result = {
                            "left": lib_plankton.pod.cull(object.left),
                            "right": lib_plankton.pod.cull(object.right),
                        };
                        convey(result);
                    }
                    else {
                        // do nothing
                    }
                };
                deferral_use(deferral_left, input, output_left => {
                    object.left = lib_plankton.pod.make_filled(output_left);
                    finish();
                });
                deferral_use(deferral_right, input, output_right => {
                    object.right = lib_plankton.pod.make_filled(output_right);
                    finish();
                });
            }));
        }
        call.deferral_compose_parallel = deferral_compose_parallel;
        /**
         * @author fenris
         * @desc repeatedly applied serial composition
         */
        function deferral_chain(members) {
            return (members.reduce(
            // (result, current) => deferral_compose_serial<type_value, type_value, type_value>(result, current),
            deferral_compose_serial, deferral_id()));
        }
        call.deferral_chain = deferral_chain;
        /**
         * @author fenris
         */
        /*
        export function deferral_bunch<type_input, type_output>(
            members : {[name : string] : type_deferral<type_input, type_output>}
        ) : type_deferral<type_input, {[name : string] : type_output}> {
            
        }
         */
    })(call = lib_plankton.call || (lib_plankton.call = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:call«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:call« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:call« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:call«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var call;
    (function (call) {
        /**
         * @author fenris
         */
        class class_deferral {
            /**
             * @author fenris
             */
            constructor(subject) {
                this.subject = subject;
            }
            /**
             * @author fenris
             */
            static _cram(subject) {
                return (new class_deferral(subject));
            }
            /**
             * @author fenris
             */
            static _tear(instance) {
                return instance.subject;
            }
            /**
             * @author fenris
             */
            static make(handler) {
                return (class_deferral._cram(call.deferral_make(handler)));
            }
            /**
             * @author fenris
             */
            use(input, procedure) {
                return (call.deferral_use(class_deferral._tear(this), input, procedure));
            }
            /**
             * @author fenris
             */
            compose_serial(second) {
                return (class_deferral._cram(call.deferral_compose_serial(class_deferral._tear(this), class_deferral._tear(second))));
            }
            /**
             * @author fenris
             */
            static chain(members) {
                return (class_deferral._cram(call.deferral_chain(members.map(member => class_deferral._tear(member)))));
            }
            /**
             * @author fenris
             */
            static wrap(function_) {
                return (class_deferral._cram(call.deferral_wrap(function_)));
            }
            /**
             * @author fenris
             */
            static const_(value) {
                return (class_deferral._cram(call.deferral_const(value)));
            }
            /**
             * @author fenris
             */
            static delay(output, delay) {
                return (class_deferral._cram(call.deferral_delay(output, delay)));
            }
        }
        call.class_deferral = class_deferral;
    })(call = lib_plankton.call || (lib_plankton.call = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:call«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:call« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:call« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:call«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var call;
    (function (call) {
        /**
         * converts the "arguments"-map into an array
         *
         * @param {Object} args
         * @author fenris
         */
        function args2list(args) {
            return Object.keys(args).map(key => args[key]);
        }
        call.args2list = args2list;
        /**
         * just the empty function; useful for some callbacks etc.
         *
         * @author fenris
         */
        function nothing() {
        }
        call.nothing = nothing;
        /**
         * just the identity; useful for some callbacks etc.; defined as function instead of const for using type parameters
         *
         * @author fenris
         */
        function id(x) {
            return x;
        }
        call.id = id;
        /**
         * just the identity; useful for some callbacks etc.
         *
         * @author fenris
         */
        function const_(x) {
            return (y => x);
        }
        call.const_ = const_;
        /**
         * composes two functions (i.e. returns a function that return the result of the successive execution of both input-functions)
         *
         * @param {function} function_f
         * @param {function} function_g
         * @author fenris
         */
        function compose(function_f, function_g) {
            return (function (x) {
                // return function_g(function_f(x));
                return function_g(function_f.apply(function_f, args2list(arguments)));
            });
        }
        call.compose = compose;
        /**
         * @author fenris
         */
        function curryfy_real(f, n) {
            switch (n) {
                case 0: {
                    throw (new Error("[curryfy] impossible"));
                    // break;
                }
                case 1: {
                    return f;
                    // break;
                }
                default: {
                    return (function (x) {
                        return (curryfy_real(function () { return f.apply(f, [x].concat(args2list(arguments))); }, n - 1));
                    });
                    // break;
                }
            }
        }
        /**
         * transforms a function with sequential input to a function with leveled input; example: add(2,3) = curryfy(add)(2)(3)
         *
         * @param {function} f
         * @return {function} the currified version of the in put function
         * @author fenris
         */
        function curryfy(f) {
            return curryfy_real(f, f.length);
        }
        call.curryfy = curryfy;
        /**
         * @author fenris
         */
        function convey(value, functions) {
            let result = value;
            functions.forEach(function_ => {
                result = function_(result);
            });
            return result;
        }
        call.convey = convey;
        /**
         * @author fenris
         */
        function timeout(procedure, delay_in_seconds) {
            return (
            /*window.*/ setTimeout(procedure, Math.floor(delay_in_seconds * 1000)));
        }
        call.timeout = timeout;
        /**
         * Promise version of "setTimeout"
         *
         * @author fenris
         */
        function defer(seconds, action) {
            return (new Promise((resolve, reject) => {
                setTimeout(() => resolve(action()), Math.floor(seconds * 1000));
            }));
        }
        call.defer = defer;
        /**
         * a definition for a value being "defined"
         *
         * @author neuc
         */
        function is_def(obj, options = {}) {
            options = Object.assign({
                "null_is_valid": false,
            }, options);
            return (!((typeof (obj) === "undefined")
                ||
                    (!options.null_is_valid && (obj === null))));
        }
        call.is_def = is_def;
        /**
         * returns the value if set and, when a type is specified, if the type is correct, if not return default_value
         *
         * @author neuc
         */
        function def_val(value, default_value, options = {}) {
            options = Object.assign({
                "type": null,
                "null_is_valid": false,
            }, options);
            if (is_def(value, { "null_is_valid": options.null_is_valid })
                &&
                    (is_def(options.type)
                        ? ((typeof (value) === options.type)
                            ||
                                ((value === null)
                                    &&
                                        options.null_is_valid))
                        : true)) {
                return value;
            }
            else {
                return default_value;
            }
        }
        call.def_val = def_val;
        ;
        /**
         * provides the call for an attribute of a class as a regular function; useful for processing lists of objects
         *
         * @param {string} name the name of the attribute
         * @return {function}
         * @author fenris
         */
        function attribute(name) {
            return (object => object[name]);
        }
        call.attribute = attribute;
        /**
         * provides a method of a class as a regular function; useful for processing lists of objects
         *
         * @param {string} name the name of the method
         * @return {function}
         * @author fenris
         */
        function method(name) {
            return (function (object) { return object[name].apply(object, args2list(arguments).slice(1)); });
        }
        call.method = method;
        /**
         * @author fenris
         */
        function distinguish(coproduct, handlers, options = {}) {
            options = Object.assign({
                "fallback": null,
            }, options);
            if (coproduct.kind in handlers) {
                const handler = handlers[coproduct.kind];
                return handler(coproduct.data);
            }
            else {
                const message = ("unhandled kind '" + coproduct.kind + "'");
                if (options.fallback !== null) {
                    console.warn(message);
                    return options.fallback(coproduct);
                }
                else {
                    throw (new Error(message));
                }
            }
        }
        call.distinguish = distinguish;
        /**
         * rate limiting algorithm, based on the idea of mana (magic power) in video games:
         * - an actor has a fixed mana capacity, i.e. the maximum amount of available power
         * - an actor has a fixed rate of mana regeneration, i.e. how fast the power is filled up (linear growth)
         * - an action has a defined mana heft, i.e. how much power is required and deducted in order to execute it
         * - mana states are represented by snapshots, i.e. the amount of power at a certain point in time
         *
         * @author fenris
         */
        async function rate_limit_check(setup, heft) {
            if (heft > setup.capacity) {
                return Promise.resolve({
                    "granted": false,
                    "seconds": null,
                });
            }
            else {
                // get current value
                const current_timestamp = (Date.now() / 1000);
                const old_snapshot_raw = (await setup.get_snapshot());
                const old_snapshot = (old_snapshot_raw
                    ??
                        { "timestamp": current_timestamp, "value": setup.capacity });
                const seconds_passed = (current_timestamp - old_snapshot.timestamp);
                const current_value = Math.min(setup.capacity, (old_snapshot.value
                    +
                        (setup.regeneration_rate
                            *
                                seconds_passed)));
                // analyze
                if (current_value < heft) {
                    // too less
                    const seconds_needed = ((setup.regeneration_rate <= 0)
                        ? null
                        : ((heft - old_snapshot.value) / setup.regeneration_rate));
                    return Promise.resolve({
                        "granted": false,
                        "seconds": ((seconds_needed === null) ? null : (seconds_needed - seconds_passed)),
                    });
                }
                else {
                    // enough -> update snapshot
                    const new_value = (current_value - heft);
                    // set_snapshot
                    if (old_snapshot_raw === null) {
                        await setup.set_snapshot({ "timestamp": current_timestamp, "value": new_value });
                    }
                    else {
                        await setup.update_snapshot(current_timestamp, (new_value - old_snapshot.value));
                    }
                    return Promise.resolve({
                        "granted": true,
                        "seconds": 0,
                    });
                }
            }
        }
        call.rate_limit_check = rate_limit_check;
    })(call = lib_plankton.call || (lib_plankton.call = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:file«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:file« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:file« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:file«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var file;
    (function (file) {
        /**
         * @author fenris
         */
        function exists(path) {
            var nm_fs = require("fs");
            return (new Promise(function (resolve, reject) {
                nm_fs.stat(path, function (error, stats) {
                    if (error) {
                        resolve(false);
                    }
                    else {
                        resolve(true);
                    }
                });
            }));
        }
        file.exists = exists;
        /**
         * @author fenris
         */
        function read(path) {
            var nm_fs = require("fs");
            return (new Promise(function (resolve, reject) {
                nm_fs.readFile(path, {
                    "encoding": "utf8",
                    "flag": "r"
                }, function (error, content) {
                    if (error == null) {
                        resolve(content);
                    }
                    else {
                        reject(error);
                    }
                });
            }));
        }
        file.read = read;
        /**
         * @author fenris
         */
        function read_buffer(path) {
            var nm_fs = require("fs");
            return (new Promise(function (resolve, reject) {
                nm_fs.readFile(path, {
                    "flag": "r"
                }, function (error, content) {
                    if (error == null) {
                        resolve(content);
                    }
                    else {
                        reject(error);
                    }
                });
            }));
        }
        file.read_buffer = read_buffer;
        /**
         * @author fenris
         */
        function read_stdin() {
            return (new Promise(function (resolve, reject) {
                var input_raw = "";
                process.stdin.setEncoding("utf8");
                process.stdin.on("readable", function () {
                    var chunk;
                    while ((chunk = process.stdin.read()) !== null) {
                        input_raw += chunk;
                    }
                });
                process.stdin.on("end", function () {
                    resolve(input_raw);
                });
            }));
        }
        file.read_stdin = read_stdin;
        /**
         * @author fenris
         */
        function write(path, content, options) {
            if (options === void 0) { options = {}; }
            options = Object.assign({
                "encoding": "utf-8"
            }, options);
            var nm_fs = require("fs");
            return (new Promise(function (resolve, reject) {
                nm_fs.writeFile(path, content, {
                    "encoding": options.encoding,
                    "flag": "w"
                }, function (error) {
                    if (error == null) {
                        resolve(undefined);
                    }
                    else {
                        reject(error);
                    }
                });
            }));
        }
        file.write = write;
        /**
         * @author fenris
         */
        function write_buffer(path, content, options) {
            if (options === void 0) { options = {}; }
            options = Object.assign({}, options);
            var nm_fs = require("fs");
            return (new Promise(function (resolve, reject) {
                nm_fs.writeFile(path, content, {
                    "flag": "w"
                }, function (error) {
                    if (error == null) {
                        resolve(undefined);
                    }
                    else {
                        reject(error);
                    }
                });
            }));
        }
        file.write_buffer = write_buffer;
        /**
         */
        function delete_(path) {
            var nm_fs = require("fs");
            return (new Promise(function (resolve, reject) {
                nm_fs.unlink(path, function () {
                    resolve(undefined);
                });
            }));
        }
        file.delete_ = delete_;
    })(file = lib_plankton.file || (lib_plankton.file = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:sha256«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:sha256« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:sha256« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:sha256«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var sha256;
    (function (sha256) {
        /**
         * @author fenris
         */
        function get(value, secret = "") {
            const nm_crypto = require("crypto");
            const sha256Hasher = nm_crypto.createHmac("sha256", secret);
            const hash = sha256Hasher.update(value).digest("hex");
            return hash;
        }
        sha256.get = get;
    })(sha256 = lib_plankton.sha256 || (lib_plankton.sha256 = {}));
})(lib_plankton || (lib_plankton = {}));
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
/*
This file is part of »bacterio-plankton:log«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:log« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:lang« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:log«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var log;
    (function (log) {
        /**
         */
        var enum_level;
        (function (enum_level) {
            enum_level[enum_level["debug"] = 0] = "debug";
            enum_level[enum_level["info"] = 1] = "info";
            enum_level[enum_level["notice"] = 2] = "notice";
            enum_level[enum_level["warning"] = 3] = "warning";
            enum_level[enum_level["error"] = 4] = "error";
        })(enum_level = log.enum_level || (log.enum_level = {}));
        ;
        /**
         */
        function level_order(level1, level2) {
            return (level1 <= level2);
        }
        log.level_order = level_order;
        /**
         */
        function level_show(level) {
            switch (level) {
                case enum_level.debug: return "debug";
                case enum_level.info: return "info";
                case enum_level.notice: return "notice";
                case enum_level.warning: return "warning";
                case enum_level.error: return "error";
                default: return "(unknown)";
            }
        }
        log.level_show = level_show;
    })(log = lib_plankton.log || (lib_plankton.log = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:log«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:log« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:lang« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:lang«. If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * @deprecated
 * @todo remove
 */
var lib_plankton;
(function (lib_plankton) {
    var log;
    (function (log) {
        /**
         * @author fenris
         */
        /*export*/ var level_stack = [0];
        function level_push(level) { level_stack.push(level); }
        log.level_push = level_push;
        function level_pop() { if (level_stack.length > 1) {
            level_stack.pop();
        } }
        log.level_pop = level_pop;
        function level_get() { return level_stack.slice(-1)[0]; }
        /*
        export function level_inc() : void {level_push(level_get()+1);}
        export function level_dec() : void {level_push(level_get()-1);}
         */
        /**
         * @author fenris
         */
        var indent_stack = [0];
        function indent_push(indent) { indent_stack.push(indent); }
        log.indent_push = indent_push;
        function indent_pop() { if (indent_stack.length > 1) {
            indent_stack.pop();
        } }
        log.indent_pop = indent_pop;
        function indent_get() { return level_stack.slice(-1)[0]; }
        function indent_inc() { level_push(level_get() + 1); }
        log.indent_inc = indent_inc;
        function indent_dec() { level_push(level_get() - 1); }
        log.indent_dec = indent_dec;
        /**
         * @author fenris
         */
        function write(_a) {
            var message = _a["message"], _b = _a["type"], type = _b === void 0 ? null : _b, _c = _a["prefix"], prefix = _c === void 0 ? null : _c, _d = _a["level"], level = _d === void 0 ? 0 : _d, _e = _a["indent"], indent = _e === void 0 ? 0 : _e;
            var entry = {
                "level": ((type === null)
                    ? lib_plankton.log.enum_level.info
                    : {
                        "debug": lib_plankton.log.enum_level.debug,
                        "info": lib_plankton.log.enum_level.info,
                        "notice": lib_plankton.log.enum_level.notice,
                        "warning": lib_plankton.log.enum_level.warning,
                        "error": lib_plankton.log.enum_level.error
                    }[type]),
                "incident": message,
                "details": {
                    "prefix": prefix,
                    "level": level,
                    "indent": indent
                }
            };
            lib_plankton.log.add(entry);
        }
        log.write = write;
    })(log = lib_plankton.log || (lib_plankton.log = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:log«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:log« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:lang« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:log«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var log;
    (function (log) {
        /**
         */
        var class_channel = /** @class */ (function () {
            function class_channel() {
            }
            return class_channel;
        }());
        log.class_channel = class_channel;
    })(log = lib_plankton.log || (lib_plankton.log = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:log«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:log« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:lang« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:log«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var log;
    (function (log) {
        /**
         * output for writing log entries to stdout
         */
        var class_channel_stdout = /** @class */ (function (_super) {
            __extends(class_channel_stdout, _super);
            function class_channel_stdout() {
                return _super !== null && _super.apply(this, arguments) || this;
            }
            /**
             */
            class_channel_stdout.prototype.add = function (entry) {
                process.stdout.write(("<" + (new Date(Date.now())).toISOString().slice(0, 19) + ">")
                    +
                        " "
                    +
                        ("[" + log.level_show(entry.level) + "]")
                    +
                        " "
                    +
                        ("" + entry.incident + "")
                    +
                        ": "
                    +
                        JSON.stringify(entry.details, undefined, "  ")
                    +
                        "\n");
            };
            return class_channel_stdout;
        }(log.class_channel));
        log.class_channel_stdout = class_channel_stdout;
    })(log = lib_plankton.log || (lib_plankton.log = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:log«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:log« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:lang« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:log«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var log;
    (function (log) {
        /**
         */
        var class_channel_file = /** @class */ (function (_super) {
            __extends(class_channel_file, _super);
            /**
             * [constructor]
             */
            function class_channel_file(path) {
                var _this = _super.call(this) || this;
                _this.path = path;
                return _this;
            }
            /**
             */
            class_channel_file.prototype.add = function (entry) {
                var _this = this;
                var nm_fs = require("fs");
                nm_fs.writeFile(this.path, {
                    "flag": "a+"
                }, (("<" + (new Date(Date.now())).toISOString().slice(0, 19) + ">")
                    +
                        " "
                    +
                        ("[" + log.level_show(entry.level) + "]")
                    +
                        " "
                    +
                        ("" + entry.incident + "")
                    +
                        ": "
                    +
                        JSON.stringify(entry.details, undefined, "  ")
                    +
                        "\n"), function (error) {
                    process.stderr.write('-- [plankton] could not add log entry to file ' + _this.path + "\n");
                });
            };
            return class_channel_file;
        }(log.class_channel));
        log.class_channel_file = class_channel_file;
    })(log = lib_plankton.log || (lib_plankton.log = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:log«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:log« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:lang« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:log«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var log;
    (function (log) {
        /**
         * output for desktop notifications via "libnotify"
         */
        var class_channel_notify = /** @class */ (function (_super) {
            __extends(class_channel_notify, _super);
            function class_channel_notify() {
                return _super !== null && _super.apply(this, arguments) || this;
            }
            /**
             */
            class_channel_notify.prototype.add = function (entry) {
                var nm_child_process = require("child_process");
                var command = ("notify-send"
                    +
                        " "
                    +
                        ("'"
                            +
                                ("[" + log.level_show(entry.level) + "]")
                            +
                                " "
                            +
                                entry.incident
                            +
                                "'")
                    +
                        " "
                    +
                        ("'"
                            +
                                (Object.keys(entry.details)
                                    .map(function (key) { return (key + ": " + JSON.stringify(entry.details[key])); })
                                    .join("\n"))
                            +
                                "'"));
                nm_child_process.exec(command, function (error, stdout, stderr) {
                    // do noting
                });
            };
            return class_channel_notify;
        }(log.class_channel));
        log.class_channel_notify = class_channel_notify;
    })(log = lib_plankton.log || (lib_plankton.log = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:log«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:log« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:lang« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:log«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var log;
    (function (log) {
        /**
         * decorator for filtering out log entries below a certain level threshold
         */
        var class_channel_minlevel = /** @class */ (function (_super) {
            __extends(class_channel_minlevel, _super);
            /**
             */
            function class_channel_minlevel(core, threshold) {
                var _this = _super.call(this) || this;
                _this.core = core;
                _this.threshold = threshold;
                return _this;
            }
            /**
             */
            class_channel_minlevel.prototype.add = function (entry) {
                if (!log.level_order(this.threshold, entry.level)) {
                    // do nothing
                }
                else {
                    this.core.add(entry);
                }
            };
            return class_channel_minlevel;
        }(log.class_channel));
        log.class_channel_minlevel = class_channel_minlevel;
    })(log = lib_plankton.log || (lib_plankton.log = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:log«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:log« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:lang« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:log«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var log;
    (function (log) {
        /**
         */
        function translate_level(level_string) {
            return {
                "debug": log.enum_level.debug,
                "info": log.enum_level.info,
                "notice": log.enum_level.notice,
                "warning": log.enum_level.warning,
                "error": log.enum_level.error
            }[level_string];
        }
        /**
         */
        function channel_make(description) {
            var _a, _b, _c, _d;
            switch (description.kind) {
                default: {
                    throw (new Error("unhandled log channel kind: " + description.kind));
                    break;
                }
                case "stdout": {
                    return (new log.class_channel_minlevel(new log.class_channel_stdout(), translate_level((_a = description.data["threshold"]) !== null && _a !== void 0 ? _a : "debug")));
                    break;
                }
                case "file": {
                    return (new log.class_channel_minlevel(new log.class_channel_file((_b = description.data["path"]) !== null && _b !== void 0 ? _b : "/tmp/plankton.log"), translate_level((_c = description.data["threshold"]) !== null && _c !== void 0 ? _c : "debug")));
                    break;
                }
                case "notify": {
                    return (new log.class_channel_minlevel(new log.class_channel_notify(), translate_level((_d = description.data["threshold"]) !== null && _d !== void 0 ? _d : "debug")));
                    break;
                }
            }
        }
        log.channel_make = channel_make;
        /**
         */
        function conf_default() {
            return [
                new log.class_channel_minlevel(new log.class_channel_stdout(), log.enum_level.notice),
                new log.class_channel_minlevel(new log.class_channel_notify(), log.enum_level.error),
            ];
        }
        log.conf_default = conf_default;
    })(log = lib_plankton.log || (lib_plankton.log = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:log«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:log« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:lang« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:log«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var log;
    (function (log) {
        /**
         */
        var _channel_stack = null;
        /**
         * pushes a new configuration on the stack and activates it
         */
        function conf_push(channels) {
            if (_channel_stack === null) {
                _channel_stack = [];
            }
            _channel_stack.push(channels);
        }
        log.conf_push = conf_push;
        /**
         * pops the current active configuration from the stack
         */
        function conf_pop() {
            if (_channel_stack.length > 0) {
                _channel_stack.pop();
            }
            else {
                // do nothing
            }
        }
        log.conf_pop = conf_pop;
        /**
         * makes the logging system ready
         */
        function setup() {
            if (_channel_stack === null) {
                _channel_stack = [];
                conf_push(log.conf_default());
            }
            else {
                // do nothing
            }
        }
        /**
         * consumes a log entry, i.e. sends it to the currently active outputs
         */
        function add(entry) {
            setup();
            _channel_stack.slice(-1)[0].forEach(function (channel) { return channel.add(entry); });
        }
        log.add = add;
        /**
         */
        function debug(incident, details) {
            if (details === void 0) { details = {}; }
            add({ "level": log.enum_level.debug, "incident": incident, "details": details });
        }
        log.debug = debug;
        /**
         */
        function info(incident, details) {
            if (details === void 0) { details = {}; }
            add({ "level": log.enum_level.info, "incident": incident, "details": details });
        }
        log.info = info;
        /**
         */
        function notice(incident, details) {
            if (details === void 0) { details = {}; }
            add({ "level": log.enum_level.notice, "incident": incident, "details": details });
        }
        log.notice = notice;
        /**
         */
        function warning(incident, details) {
            if (details === void 0) { details = {}; }
            add({ "level": log.enum_level.warning, "incident": incident, "details": details });
        }
        log.warning = warning;
        /**
         */
        function error(incident, details) {
            if (details === void 0) { details = {}; }
            add({ "level": log.enum_level.error, "incident": incident, "details": details });
        }
        log.error = error;
    })(log = lib_plankton.log || (lib_plankton.log = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:string«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:string« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:string« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:string«. If not, see <http://www.gnu.org/licenses/>.
 */
var plain_text_to_html = function (text) {
    let ret = text;
    ret = ret.replace(/  /g, "&nbsp;&nbsp;"); // convert multiple whitespace to forced ones
    ret = ret.split("\n").join("<br/>");
    return ret;
};
/**
 * @desc makes a valid
 */
var format_sentence = function (str, rtl = false, caseSense = true) {
    if (str === "") {
        return str;
    }
    else {
        let marks = {
            ".": true,
            "?": true,
            "!": true
        };
        let default_mark = ".";
        let ret = str.split("");
        if (!rtl) {
            ret[0] = ret[0].toLocaleUpperCase();
            if (!(ret[ret.length - 1] in marks)) {
                ret.push(default_mark);
            }
        }
        else {
            ret[ret.length - 1] = ret[ret.length - 1].toLocaleUpperCase();
            if (!(ret[0] in marks)) {
                ret.unshift(default_mark);
            }
        }
        return ret.join("");
    }
};
var fill_string_template = function (template_string, object, fabric = function (object, key) { return object[key]; }, delimiter = "%", default_string = null, sloppy) {
    function get_tags(str) {
        let r = new RegExp(delimiter + "[^\\s^" + delimiter + "]+" + delimiter, "gi");
        return ((str.match(r) || []).map(function (e) {
            return e.slice(delimiter.length, e.length - delimiter.length);
        }));
    }
    function replace_tag(str, tag, value) {
        let r = new RegExp(delimiter + tag + delimiter, "gi");
        return str.replace(r, value);
    }
    function replace_tags(str, obj) {
        return (get_tags(str).reduce(function (ret, key) {
            let value = "";
            try {
                value = fabric(obj, key);
                if ((!sloppy && (value === void 0)) || (sloppy && (value == void 0))) {
                    value = default_string;
                }
            }
            catch (e) {
                console.warn("invalid placeholder " + key);
                value = default_string;
            }
            return replace_tag(ret, key, value);
        }, str));
    }
    return replace_tags(template_string, object);
};
var make_string_template = function (_template, _fabrics = {}) {
    function replace_tag(str, tag, value) {
        var r = new RegExp("%" + tag + "%", "gi");
        return str.replace(r, value);
    }
    function replace_tags(str, obj) {
        return (Object.keys(obj).reduce(function (ret, key) {
            return replace_tag(ret, key, _fabrics[key] || obj[key]);
        }, str));
    }
    return (function (tags) {
        return replace_tags(_template, tags);
    });
};
var make_eml_header = (function () {
    let _template = "";
    _template += "From: %from%\n";
    _template += "To: %recipient%\n";
    _template += "Subject: %subject%\n";
    _template += "X-Mailer: greenscale-plankton.emlgen\n";
    return make_string_template(_template);
})();
var make_eml_body = (function () {
    let exports = {};
    exports["simple_body"] = make_string_template("Content-Type: %contenttype%\n\n%body%\n\n");
    // very basic implementation
    // parts = [{contenttype:"text/html; charset=UTF-8", body: "<h1>foo</h1>" }, {...}]
    exports["body_boundrary"] = function (parts, boundrary) {
        let _template = "";
        _template += "--%boundrary%\n";
        _template += "Content-Type: %contenttype%\n\n%body%\n\n";
        //_template += "--%boundrary%--\n\n";
        let maker = make_string_template(_template);
        return (parts.reduce(function (prev, curr) {
            curr.boundrary = boundrary;
            return [prev, maker(curr)].join("");
        }, ""));
    };
    // body must be base64 encoded!
    exports["attachment_boundrary"] = function (parts, boundrary) {
        let _template = "";
        _template += "--%boundrary%\n";
        _template += "Content-Type: %contenttype%\n";
        _template += "Content-Transfer-Encoding: base64\n";
        _template += "Content-Disposition: %disposition%; filename=\"%name%\"\n\n";
        _template += "%body%\n\n";
        //_template += "--%boundrary%--\n\n";
        let maker = make_string_template(_template);
        return (parts.reduce(function (prev, curr) {
            curr.boundrary = boundrary;
            if (curr.disposition === void 0)
                curr.disposition = "inline";
            return [prev, maker(curr)].join("");
        }, ""));
    };
    exports["gen_boundrary"] = function () {
        return ("xxxxxxxxxxxxxxxxxxxxxx".replace(/[xy]/g, function (c) {
            let r = crypto.getRandomValues(new Uint8Array(1))[0] % 16 | 0, v = c == "x" ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        }));
    };
    // simple implementation without alternatives (old rfc)
    exports["complete_boundrary"] = function (bodyparts, attachments) {
        let ret = "";
        let boundrary = exports["gen_boundrary"]();
        ret += exports["body_boundrary"](bodyparts, boundrary);
        ret += exports["attachment_boundrary"](attachments, boundrary);
        ret += "--" + boundrary + "--\n\nINVISIBLE!!!!";
        return (exports["simple_body"]({
            "contenttype": sprintf("multipart/mixed; boundary=%s", [boundrary]),
            "body": ret
        }));
    };
    return exports;
})();
/*
This file is part of »bacterio-plankton:string«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:string« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:string« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:string«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var string;
    (function (string) {
        /**
         * @author fenris
         */
        const hexdigits = 4;
        /**
         * @author fenris
         */
        const index_max = (1 << (4 * hexdigits));
        /**
         * @author fenris
         */
        var index_is = 0;
        /**
         * @author neuc,frac
         */
        function empty(str) {
            return (str.trim() === "");
        }
        string.empty = empty;
        /**
         * @desc returns a unique string
         * @param {string} prefix an optional prefix for the generated string
         * @return {string}
         * @author fenris
         */
        function generate(prefix = "string_") {
            if (index_is > index_max) {
                throw (new Error("[string_generate] out of valid indices"));
            }
            else {
                return string.sprintf(prefix + "%0" + hexdigits.toString() + "X", [index_is++]);
            }
        }
        string.generate = generate;
        /**
         * @author fenris
         */
        function join(parts, glue = " ") {
            if (parts.length == 0) {
                return "";
            }
            else {
                return parts.join(glue);
            }
        }
        string.join = join;
        /**
         * @desc splits a string, but returns an empty list, if the string is empty
         * @param {string} chain
         * @param {string} separator
         * @return {Array<string>}
         * @author fenris
         */
        function split(chain, separator = " ") {
            if (chain.length == 0) {
                return [];
            }
            else {
                return chain.split(separator);
            }
        }
        string.split = split;
        /**
         * @author neu3no
         */
        function explode(str, needle, max) {
            let temp = str.split(needle);
            const right = temp.splice(max - 1);
            temp.push(right.join(needle));
            return temp;
        }
        string.explode = explode;
        /**
         * @desc concats a given word with itself n times
         * @param {string} word
         * @param {int}
         * @return {string}
         * @author fenris
         */
        function repeat(word, count) {
            // return ((count == 0) ? "" : (word + repeat(word, count-1)));
            let result = "";
            for (let n = 0; n < count; n += 1) {
                result += word;
            }
            return result;
        }
        string.repeat = repeat;
        /**
         * @desc lengthens a string by repeatedly appending or prepending another string
         * @param {string} word the string to pad
         * @param {int} length the length, which the result shall have
         * @param {string} symbol the string, which will be added (multiple times)
         * @param {boolean} [prepend]; whether to prepend (~true) or append (~false); default: false
         * @return {string} the padded string
         * @author fenris
         */
        function pad(word, length, symbol = " ", mode = "append") {
            switch (mode) {
                case "prepend": {
                    // insert symbols only at the beginning
                    while (word.length < length)
                        word = symbol + word;
                    return word.substring(word.length - length);
                    break;
                }
                case "append": {
                    // insert symbols only at the end
                    while (word.length < length)
                        word = word + symbol;
                    return word.substring(0, length);
                    break;
                }
                case "widen": {
                    // insert symbols at both sides
                    let left = (((length - word.length) & 1) === 0);
                    while (word.length < length) {
                        word = (left
                            ? (symbol + word)
                            : (word + symbol));
                        left = (!left);
                    }
                    return word.substring(0, length);
                    break;
                }
                default: {
                    const message = ("unhandled mode '" + mode + "'");
                    console.warn(message);
                    return word;
                    break;
                }
            }
        }
        string.pad = pad;
        /**
         * @desc checks if a given string conttains a certain substring
         * @param {string} string
         * @param {string} part
         * @return {boolean}
         * @author fenris
         */
        function contains(chain, part) {
            if (typeof (chain) !== "string") {
                return false;
            }
            return (chain.indexOf(part) >= 0);
        }
        string.contains = contains;
        /**
         * @desc checks if a given string starts with a certain substring
         * @param {string} string
         * @param {string} part
         * @return {boolean}
         * @author fenris
         */
        function startsWith(chain, part) {
            if (typeof (chain) !== "string") {
                return false;
            }
            // return (string.indexOf(part) === 0);
            return ((function (m, n) {
                if (n === 0) {
                    return true;
                }
                else {
                    if (m === 0) {
                        return false;
                    }
                    else {
                        return ((chain[0] == part[0])
                            &&
                                startsWith(chain.substring(1), part.substring(1)));
                    }
                }
            })(chain.length, part.length));
        }
        string.startsWith = startsWith;
        /**
         * @desc checks if a given string ends with a certain substring
         * @param {string} string
         * @param {string} part
         * @return {boolean}
         * @author fenris
         */
        function endsWith(chain, part) {
            if (typeof (chain) !== "string") {
                return false;
            }
            // return (string.lastIndexOf(part) === string.length-part.length);
            return ((function (m, n) {
                if (n === 0) {
                    return true;
                }
                else {
                    if (m === 0) {
                        return false;
                    }
                    else {
                        // console.info(("(" + string[m-1] + " == " + part[n-1] + ")") + " = " + String(string[m-1] == part[n-1]));
                        return ((chain[m - 1] === part[n - 1])
                            &&
                                endsWith(chain.substring(0, m - 1), part.substring(0, n - 1)));
                    }
                }
            })(chain.length, part.length));
        }
        string.endsWith = endsWith;
        /**
         * @desc count the occourrences of a string in a string
         * @param string haystack_string the string wich should be examined
         * @param string needle_string the string which should be counted
         * @author neuc
         */
        function count_occourrences(haystack_string, needle_string, check_escape) {
            let cnt = 0;
            let pos = -1;
            do {
                pos = haystack_string.indexOf(needle_string, pos + 1);
                if ((!check_escape) || (haystack_string[pos - 1] != "\\")) {
                    cnt++;
                }
            } while (pos >= 0);
            return (cnt - 1);
        }
        string.count_occourrences = count_occourrences;
        /**
         * @author fenris
         */
        function replace(str, replacements, options = {}) {
            options = Object.assign({}, options);
            let result = str;
            replacements.forEach(replacement => {
                lib_plankton.log.debug("lib_plankton.string.replace", {
                    "from": replacement.from,
                    "to": replacement.to,
                });
                result = result.replace(new RegExp(replacement.from, "g"), replacement.to);
            });
            return result;
        }
        string.replace = replace;
        /**
         * @desc replaces occurences of "{{name}}" in a string by the corresponding values of an argument object
         * @author fenris
         */
        function coin(str, args, options = {}) {
            options = Object.assign({
                "legacy": false,
                "open": "{{",
                "close": "}}",
            }, options);
            Object.keys(args).forEach((key) => {
                // old syntax
                {
                    if (options.legacy) {
                        const value = args[key];
                        const regexp_argument = new RegExp("\\${" + key + "}", "g");
                        lib_plankton.log.debug("lib_plankton.string.coin", {
                            "key": key,
                            "regex": regexp_argument.toString(),
                            "value": value,
                        });
                        str = str.replace(regexp_argument, value);
                    }
                }
                // new syntax
                {
                    const value = args[key];
                    const regexp_argument = new RegExp(options.open + key + options.close, "g");
                    lib_plankton.log.debug("lib_plankton.string.coin", {
                        "key": key,
                        "regex": regexp_argument.toString(),
                        "value": value,
                    });
                    str = str.replace(regexp_argument, value);
                }
            });
            return str;
        }
        string.coin = coin;
        /**
         * @author fenris
         * @deprecated use limit
         */
        function cut(str, length, delimiter = "…") {
            if (str.length <= length) {
                return str;
            }
            else {
                return (str.slice(0, length - delimiter.length) + delimiter);
            }
        }
        string.cut = cut;
        /**
         */
        function limit(str, options = {}) {
            options = Object.assign({
                "length": 120,
                "indicator": "…",
            }, options);
            return ((str.length <= options.length)
                ? str
                : (str.slice(0, options.length - options.indicator.length) + options.indicator));
        }
        string.limit = limit;
        /**
         */
        function slice(str, size) {
            let slices = [];
            let rest = str;
            while (rest.length > 0) {
                slices.push(rest.slice(0, size));
                rest = rest.slice(size);
            }
            return slices;
        }
        string.slice = slice;
    })(string = lib_plankton.string || (lib_plankton.string = {}));
})(lib_plankton || (lib_plankton = {}));
/**
 * @deprecated
 */
var lib_string;
(function (lib_string) {
    lib_string.empty = lib_plankton.string.empty;
    lib_string.generate = lib_plankton.string.generate;
    lib_string.split = lib_plankton.string.split;
    lib_string.explode = lib_plankton.string.repeat;
    lib_string.repeat = lib_plankton.string.repeat;
    lib_string.pad = lib_plankton.string.pad;
    lib_string.contains = lib_plankton.string.contains;
    lib_string.startsWith = lib_plankton.string.startsWith;
    lib_string.endsWith = lib_plankton.string.endsWith;
    lib_string.count_occourrences = lib_plankton.string.count_occourrences;
    lib_string.coin = lib_plankton.string.coin;
    lib_string.stance = lib_plankton.string.coin;
    lib_string.cut = lib_plankton.string.cut;
})(lib_string || (lib_string = {}));
/*
This file is part of »bacterio-plankton:string«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:string« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:string« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:string«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var string;
    (function (string) {
        var pattern = /%([-+#0 ]*)([0-9]*)[\.]{0,1}([0-9]*)([\w]{1})/;
        var gpattern = /%([-+#0 ]*)([0-9]*)[\.]{0,1}([0-9]*)([\w]{1})/g;
        function split_format(format) {
            var tmp = format.match(pattern);
            if (tmp === null)
                return null;
            return {
                'flags': tmp[1].split(""),
                'width': Number(tmp[2]),
                'precision': tmp[3] === '' ? null : Number(tmp[3]),
                'specifier': tmp[4],
                'string': format
            };
        }
        function make_err(format, arg, should) {
            return ("[sprintf]" + " " + "argument for '" + format.string + "' has to be '" + should + "' but '" + arg + "' is '" + typeof arg + "'!");
        }
        function test_arg(format, arg, should) {
            if (typeof arg !== should) {
                console.warn(make_err(format, arg, should));
                return false;
            }
            return true;
        }
        function string_fill(str, char, len, left) {
            while (str.length < len) {
                if (left) {
                    str += char;
                }
                else {
                    str = char + str;
                }
            }
            return str;
        }
        /**
         * the known_parameters are used to parse the different identifiers for the welln known syntax:
         *          flag   width   precision   identifier
         *      %{[0#+- ]}{[0-9]*}.{[0-9]*}[fFdiueEgGsoxXaAsn]
         * flags:
         * 0    -   fill with '0' instead of ' ' if the string length < width
         * #    -   not implemented
         * -    -   left-justified -> fill on the right side to reach width
         * +    -   force using '+' on positive numbers
         * ' '  -   add a single space before positive numbers
         *
         * identifiers
         * %f, %F       -   interpret given number as float, width: the minimal total width (fill with ' ' or '0' if the
         *                  resulting string is too short, precision: cut more then given decimal places
         * %d, %i, %u   -   interpret number as integer, decimal places will be cut. width: like float, precision:
         *                  fill with '0' on right side until length given in precision is reached
         * %e           -   interpret as float and write as scientifical number, width & precision like in float
         * %E           -   same es %e but uppercase 'E'
         * %g           -   use the shortest string of %f or %e
         * %G           -   use the shortest string of %E or %E
         * %s           -   simply print a string
         * %o           -   print the given number in octal notation
         * %x           -   print the given number in hex notation
         * %X           -   same as %x but with uppercase characters
         * %a           -   alias to %x
         * %A           -   alias to %X
         * %n           -   just print nothing
         * @type {{}}
         */
        var known_params = {};
        known_params["f"] = function (format, arg) {
            if (!test_arg(format, arg, "number"))
                return "Ø";
            var tmp = Math.abs(arg);
            var sign = (arg < 0) ? -1 : 1;
            var tmp_result = null;
            if (format.precision !== null) {
                tmp = Math.floor(Math.pow(10, format.precision) * tmp) / Math.pow(10, format.precision);
                var tmp_ = (tmp * sign).toString().split(".");
                if (tmp_.length === 1)
                    tmp_.push("");
                tmp_[1] = string_fill(tmp_[1], "0", format.precision, true);
                tmp_result = tmp_.join(".");
            }
            else {
                tmp_result = (sign * tmp).toString();
            }
            if ((format.flags.indexOf(" ") >= 0) && (arg >= 0)) {
                tmp_result = " " + tmp;
            }
            else if ((format.flags.indexOf("+") >= 0) && (arg >= 0)) {
                tmp_result = "+" + tmp;
            }
            tmp_result = string_fill(tmp, (format.flags.indexOf("0") >= 0) ? "0" : " ", format.width, (format.flags.indexOf("-") >= 0));
            return tmp_result;
        };
        known_params["F"] = known_params["f"];
        known_params["d"] = function (format, arg) {
            if (!test_arg(format, arg, 'number'))
                return 'Ø';
            var tmp = (((arg < 0 && format.specifier !== 'u') ? -1 : 1) * Math.floor(Math.abs(arg))).toString();
            if ((format.specifier === 'd' || format.specifier === 'i') && format.flags.indexOf(' ') >= 0 && arg >= 0) {
                tmp = ' ' + tmp;
            }
            else if ((format.specifier === 'd' || format.specifier === 'i') && format.flags.indexOf('+') >= 0 && arg >= 0) {
                tmp = '+' + tmp;
            }
            tmp = string_fill(tmp, format.flags.indexOf('0') >= 0 ? '0' : ' ', format.width, format.flags.indexOf('-') >= 0);
            tmp = string_fill(tmp, '0', format.precision === null ? 0 : format.precision, false);
            return tmp;
        };
        known_params["i"] = known_params["d"];
        known_params["u"] = known_params["d"];
        known_params["e"] = function (format, arg) {
            if (!test_arg(format, arg, 'number'))
                return 'Ø';
            var tmp = arg.toExponential(format.precision === null ? undefined : format.precision).toString();
            if (format.flags.indexOf(' ') >= 0 && arg >= 0) {
                tmp = ' ' + tmp;
            }
            else if (format.flags.indexOf('+') >= 0 && arg >= 0) {
                tmp = '+' + tmp;
            }
            tmp = string_fill(tmp, format.flags.indexOf('0') >= 0 ? '0' : ' ', format.width, format.flags.indexOf('-') >= 0);
            return tmp;
        };
        known_params["E"] = function (format, arg) {
            return known_params["e"](format, arg).toUpperCase();
        };
        known_params["g"] = function (format, arg) {
            if (!test_arg(format, arg, 'number'))
                return 'Ø';
            var tmpf = known_params["f"](format, arg);
            var tmpe = known_params["e"](format, arg);
            if (tmpf.length < tmpe.length) {
                return tmpf;
            }
            else {
                return tmpe;
            }
        };
        known_params["G"] = function (format, arg) {
            return known_params["g"](format, arg).toUpperCase();
        };
        known_params["s"] = function (format, arg) {
            if (!test_arg(format, arg, 'string'))
                return 'o.O';
            var tmp = format.precision !== null ? arg.substr(0, format.precision) : arg;
            tmp = string_fill(tmp, format.flags.indexOf('0') >= 0 ? '0' : ' ', format.width, format.flags.indexOf('-') >= 0);
            return tmp;
        };
        known_params["o"] = function (format, arg) {
            if (!test_arg(format, arg, 'number'))
                return 'Ø';
            var tmp = Math.floor(Math.round(Math.abs(arg))) * ((arg < 0) ? -1 : 1);
            return known_params["s"](format, tmp.toString(8));
        };
        known_params["x"] = function (format, arg) {
            if (!test_arg(format, arg, 'number'))
                return 'Ø';
            var tmp = Math.floor(Math.round(Math.abs(arg))) * ((arg < 0) ? -1 : 1);
            return known_params["s"](format, tmp.toString(16));
        };
        known_params["a"] = known_params["x"];
        known_params["X"] = function (format, arg) {
            if (!test_arg(format, arg, 'number'))
                return 'Ø';
            return known_params["x"](format, arg).toUpperCase();
        };
        known_params["A"] = known_params["X"];
        known_params["c"] = function (format, arg) {
            var tmp = "";
            if (typeof arg === "number") {
                tmp = String.fromCharCode(arg);
            }
            else if ((typeof arg === "string") && (arg.length === 1)) {
                tmp = arg[0];
            }
            else {
                console.warn(make_err(format, arg, "number|string") + " and if string it needs to have the length of 1!");
            }
            return known_params["s"](format, tmp);
        };
        known_params["n"] = function () {
            return "";
        };
        var decompose = function (chain, regexp) {
            var result = regexp.exec(chain);
            if (result == null) {
                return null;
            }
            else {
                var front = chain.substring(0, result.index);
                var back = chain.substring(result.index + result[0].length);
                return { "front": front, "match": result[0], "back": back };
            }
        };
        /**
         * an implementation of c sprintf
         * @param {string} string format string
         * @param {array} args arguments which should be filled into
         * @returns {string}
         */
        string.sprintf = function (input, args = [], original = null) {
            if (original == null)
                original = input;
            var components = decompose(input, pattern);
            if (components == null) {
                if (args.length > 0) {
                    console.warn("[sprintf] superfluous arguments while formatting '" + original + "': ", args);
                }
                return input;
            }
            else {
                var arg;
                var rest;
                if (args.length > 0) {
                    arg = args[0];
                    rest = args.slice(1);
                }
                else {
                    console.warn("[sprintf] out of arguments while formatting '" + original + "'");
                    arg = null;
                    rest = [];
                    return input;
                }
                var fmt = split_format(components["match"]);
                return (components["front"]
                    + known_params[fmt.specifier](fmt, arg)
                    + string.sprintf(components["back"], rest, original));
            }
        };
        /**
         * an implementation of c printf
         * @param {string} string format string
         * @param {array} args arguments which should be filled into
         * @returns {string}
         */
        function printf(format, args) {
            console.log(string.sprintf(format, args));
        }
        string.printf = printf;
    })(string = lib_plankton.string || (lib_plankton.string = {}));
})(lib_plankton || (lib_plankton = {}));
var sprintf = lib_plankton.string.sprintf;
var printf = lib_plankton.string.printf;
/*
This file is part of »bacterio-plankton:string«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:string« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:string« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:string«. If not, see <http://www.gnu.org/licenses/>.
 */
var make_logger = (function () {
    var _loggers = {};
    var make_logger = function (prefix, current_loglevel) {
        var log = [];
        var level = [
            "LOG", "INFO", "WARNING", "DEBUG"
        ];
        var logger = function (obj, lvl) {
            var txt = obj.txt || obj;
            if (lvl == void 0)
                lvl = 0;
            var date = new Date();
            log.push({
                "message": sprintf("%s [%s:%s] %s", [date.toString(), level[lvl], prefix, txt]),
                "timeStamp": +(date)
            });
            if (lvl <= current_loglevel) {
                var msg = ["[" + prefix + "]", txt];
                if (obj.arg)
                    msg = ["[" + prefix + "]"].concat(Array.prototype.slice.call(obj.arg));
                if (lvl === 0)
                    console["_log"].apply(console, msg);
                else if (lvl === 1)
                    console["_info"].apply(console, msg);
                else if (lvl === 2)
                    console["_warn"].apply(console, msg);
                else if (lvl >= 3)
                    console["_log"].apply(console, msg);
            }
        };
        _loggers[prefix] = {
            "logger": logger,
            "log": log
        };
        return logger;
    };
    make_logger["loggers"] = _loggers;
    make_logger["complete_log"] = function () {
        var logs = Object.keys(_loggers)
            .reduce(function (p, c) {
            return [].concat(p, _loggers[c].log);
        }, []);
        logs.sort(function (x, y) {
            return ((x.timeStamp > y.timeStamp) ? -1 : +1);
        });
        return logs.map(function (x, i, a) {
            return x.message;
        });
    };
    if ( /*!track_exports*/true) {
        var _log_all = function (log, lvl, next = function () { }) {
            return function () {
                var msg = [];
                for (var i = 0; i < arguments.length; i++) {
                    if (typeof arguments[i] === "string") {
                        msg.push(arguments[i]);
                    }
                    else {
                        msg.push(JSON.stringify(arguments[i]));
                    }
                }
                var obj = {
                    txt: msg.join("\t"),
                    arg: arguments
                };
                log(obj, lvl);
                next();
            };
        };
        {
            var __warn = make_logger("deprecated console.warn", 99);
            var __error = make_logger("deprecated console.error", 99);
            var __log = make_logger("deprecated console.log", 99);
            var __info = make_logger("deprecated console.info", 99);
            // bad ass
            console["_log"] = console.log;
            console["_error"] = console.error;
            console["_warn"] = console.warn;
            console["_info"] = console.info;
            /*
            console["log"] = _log_all(__log, 0);
            console["error"] = _log_all(__error, 2);
            console["warn"] = _log_all(__warn, 2);
            console["info"] = _log_all(__info, 0);
             */
        }
        /*
        {
            make_logger["send_log"] = function(){
                eml_log(
                    function () {
                        alert("fehlerbericht wurde gesendet!");
                    }
                );
            };
            var error_log = make_logger("global.error", 99);
            window.onerror = _log_all(
                error_log,
                1,
                function(){
                    if (global_config == undefined) {
                        return false;
                    }
                    if (global_config.report_error) {
                        make_logger["send_log"]();
                    }
                }
            );
        }
         */
    }
    return make_logger;
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
/*
This file is part of »bacterio-plankton:database«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:database« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:database« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:database«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var database;
    (function (database) {
        /**
         */
        let enum_type;
        (function (enum_type) {
            enum_type["boolean"] = "boolean";
            enum_type["integer"] = "integer";
            enum_type["string_short"] = "string_short";
            enum_type["string_medium"] = "string_medium";
            enum_type["string_long"] = "string_long";
            enum_type["float"] = "float";
        })(enum_type = database.enum_type || (database.enum_type = {}));
    })(database = lib_plankton.database || (lib_plankton.database = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:database«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:database« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:database« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:database«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var database;
    (function (database) {
        /**
         * @todo default case?
         */
        function sql_common_value_format(value) {
            if (value === undefined) {
                throw (new Error("can not format undefined"));
            }
            else {
                if (value === null) {
                    return "NULL";
                }
                else {
                    switch (typeof (value)) {
                        case "boolean": {
                            return (value ? "TRUE" : "FALSE");
                            break;
                        }
                        case "number": {
                            return value.toString();
                            break;
                        }
                        case "string": {
                            return ("'" + value + "'");
                            break;
                        }
                    }
                }
            }
        }
        database.sql_common_value_format = sql_common_value_format;
        /**
         */
        function sql_common_formulation_create_table(description_create_table, options) {
            var _a, _b, _c, _d, _e, _f;
            options = Object.assign({
                "auto_increment_keyword": "AUTO INCREMENT",
                "omit_comments": false,
                "type_map": {
                    "boolean": "BOOLEAN",
                    "integer": "INTEGER",
                    "string_short": "VARCHAR(63)",
                    "string_medium": "VARCHAR(255)",
                    "string_long": "TEXT",
                    "float": "REAL",
                },
            }, options);
            return {
                "template": lib_plankton.string.coin("CREATE TABLE\n\t`{{name}}`(\n{{entries}}\n\t){{comment}}\n;", {
                    "name": description_create_table.name,
                    "comment": ((options.omit_comments
                        ||
                            (((_a = description_create_table.description) !== null && _a !== void 0 ? _a : null) === null))
                        ? ""
                        : lib_plankton.string.coin(" COMMENT '{{comment}}'", {
                            "comment": description_create_table.description,
                        })),
                    "entries": (([]
                        // key field
                        .concat((((_b = description_create_table.key_field) !== null && _b !== void 0 ? _b : null) === null)
                        ? []
                        : lib_plankton.string.coin("`{{name}}` {{parameters}}", {
                            "name": description_create_table.key_field.name,
                            "parameters": (([]
                                // type
                                .concat([
                                options.type_map[(_c = description_create_table.key_field.type) !== null && _c !== void 0 ? _c : "integer"],
                            ])
                                // primary key
                                .concat([
                                "PRIMARY KEY",
                            ])
                                // auto increment
                                .concat((((_d = description_create_table.key_field.auto_increment) !== null && _d !== void 0 ? _d : true) === null)
                                ? []
                                : [
                                    options.auto_increment_keyword,
                                ]))
                                .join(" ")),
                        }))
                        // data fields
                        .concat(((_e = description_create_table.data_fields) !== null && _e !== void 0 ? _e : [])
                        .map((data_field) => {
                        var _a, _b;
                        return lib_plankton.string.coin("`{{name}}` {{parameters}}", {
                            "name": data_field.name,
                            "parameters": (([]
                                // type
                                .concat([
                                options.type_map[data_field.type],
                            ])
                                // nullability
                                .concat((!((_a = data_field.nullable) !== null && _a !== void 0 ? _a : false))
                                ? []
                                : ["NULL"])
                                // default
                                .concat((!data_field.hasOwnProperty("default"))
                                ? []
                                : [
                                    lib_plankton.string.coin(" DEFAULT {{value}}", {
                                        "value": sql_common_value_format(data_field.default)
                                    }),
                                ])
                                // comment
                                .concat((options.omit_comments
                                ||
                                    (((_b = data_field.description) !== null && _b !== void 0 ? _b : null) === null))
                                ? []
                                : [
                                    lib_plankton.string.coin("COMMENT '{{comment}}'", {
                                        "comment": data_field.description,
                                    }),
                                ]))
                                .join(" "))
                        });
                    }))
                        // constraints
                        .concat(((_f = description_create_table.constraints) !== null && _f !== void 0 ? _f : [])
                        .map((constraint) => {
                        switch (constraint.kind) {
                            default: {
                                throw (new Error("unhandled constraint kind: " + constraint.kind));
                                break;
                            }
                            case "foreign_key": {
                                return lib_plankton.string.coin("FOREIGN KEY ({{fields}}) REFERENCES `{{reference_name}}`({{reference_fields}})", {
                                    "fields": (constraint.parameters["fields"]
                                        .map(x => ('`' + x + '`'))
                                        .join(",")),
                                    "reference_name": constraint.parameters["reference"]["name"],
                                    "reference_fields": (constraint.parameters["reference"]["fields"]
                                        .map(x => ('`' + x + '`'))
                                        .join(",")),
                                });
                                break;
                            }
                            case "unique": {
                                return lib_plankton.string.coin("UNIQUE ({{fields}})", {
                                    "fields": (constraint.parameters["fields"]
                                        .map(x => ('`' + x + '`'))
                                        .join(",")),
                                });
                                break;
                            }
                        }
                    })))
                        .map(x => ("\t\t" + x))
                        .join(",\n")),
                }),
                "arguments": {}
            };
        }
        database.sql_common_formulation_create_table = sql_common_formulation_create_table;
        /**
         */
        function sql_common_formulation_insert(description_insert) {
            const field_names = Object.keys(description_insert.values);
            return {
                "template": lib_plankton.string.coin("INSERT INTO `{{table_name}}`({{schema}}) VALUES ({{values}});", {
                    "table_name": description_insert.table_name,
                    "schema": (field_names
                        .map((field_name) => lib_plankton.string.coin("`{{name}}`", {
                        "name": field_name,
                    }))
                        .join(",")),
                    "values": (field_names
                        .map((field_name) => lib_plankton.string.coin("$value_{{name}}", {
                        "name": field_name,
                    }))
                        .join(",")),
                }),
                "arguments": Object.fromEntries(Object.entries(description_insert.values)
                    .map(([name, value]) => ([
                    lib_plankton.string.coin("value_{{name}}", {
                        "name": name,
                    }),
                    value
                ]))),
            };
        }
        database.sql_common_formulation_insert = sql_common_formulation_insert;
        /**
         */
        function sql_common_formulation_update(description_update) {
            var _a, _b;
            const field_names = Object.keys(description_update.values);
            return {
                "template": lib_plankton.string.coin("UPDATE `{{table_name}}` SET {{assignments}}{{macro_where}};", {
                    "table_name": description_update.table_name,
                    "assignments": (field_names
                        .map((field_name) => lib_plankton.string.coin("`{{name}}` = $value_{{name}}", {
                        "name": field_name,
                    }))
                        .join(", ")),
                    "macro_where": ((((_a = description_update.condition) !== null && _a !== void 0 ? _a : null) === null)
                        ? ""
                        : lib_plankton.string.coin(" WHERE {{expression}}", {
                            "expression": description_update.condition,
                        })),
                }),
                "arguments": Object.assign(Object.fromEntries(Object.entries(description_update.values)
                    .map(([name, value]) => ([
                    lib_plankton.string.coin("value_{{name}}", {
                        "name": name,
                    }),
                    value
                ]))), ((_b = description_update.arguments) !== null && _b !== void 0 ? _b : {}))
            };
        }
        database.sql_common_formulation_update = sql_common_formulation_update;
        /**
         */
        function sql_common_formulation_delete(description_delete) {
            var _a, _b;
            return {
                "template": lib_plankton.string.coin("DELETE FROM `{{table_name}}`{{macro_where}};", {
                    "table_name": description_delete.table_name,
                    "macro_where": ((((_a = description_delete.condition) !== null && _a !== void 0 ? _a : null) === null)
                        ? ""
                        : lib_plankton.string.coin(" WHERE {{expression}}", {
                            "expression": description_delete.condition,
                        })),
                }),
                "arguments": Object.assign({}, ((_b = description_delete.arguments) !== null && _b !== void 0 ? _b : {})),
            };
        }
        database.sql_common_formulation_delete = sql_common_formulation_delete;
        /**
         */
        function sql_common_formulation_select(description_select) {
            var _a, _b, _c, _d, _e, _f, _g;
            return {
                "template": lib_plankton.string.coin("SELECT {{fields}} FROM `{{source}}`{{macro_where}}{{macro_group_by}}{{macro_having}}{{macro_order_by}}{{macro_limit}};", {
                    "source": description_select.source,
                    "fields": ((((_a = description_select.fields) !== null && _a !== void 0 ? _a : null) === null)
                        ? "*"
                        : (description_select.fields
                            .map(field_name => lib_plankton.string.coin("`{{name}}`", { "name": field_name }))
                            .join(","))),
                    "macro_where": ((((_b = description_select.condition) !== null && _b !== void 0 ? _b : null) === null)
                        ? ""
                        : lib_plankton.string.coin(" WHERE {{expression}}", {
                            "expression": description_select.condition,
                        })),
                    "macro_group_by": ((((_c = description_select.group_by) !== null && _c !== void 0 ? _c : null) === null)
                        ? ""
                        : lib_plankton.string.coin(" GROUP BY {{expression}}", {
                            "expression": description_select.group_by,
                        })),
                    "macro_having": ((((_d = description_select.having) !== null && _d !== void 0 ? _d : null) === null)
                        ? ""
                        : lib_plankton.string.coin(" HAVING {{expression}}", {
                            "expression": description_select.having,
                        })),
                    "macro_order_by": ((((_e = description_select.order_by) !== null && _e !== void 0 ? _e : null) === null)
                        ? ""
                        : lib_plankton.string.coin(" ORDER BY {{expression}}", {
                            "expression": description_select.order_by,
                        })),
                    "macro_limit": ((((_f = description_select.limit) !== null && _f !== void 0 ? _f : null) === null)
                        ? ""
                        : lib_plankton.string.coin(" LIMIT {{expression}}", {
                            "expression": description_select.limit.toFixed(0),
                        })),
                }),
                "arguments": Object.assign({}, ((_g = description_select.arguments) !== null && _g !== void 0 ? _g : {})),
            };
        }
        database.sql_common_formulation_select = sql_common_formulation_select;
    })(database = lib_plankton.database || (lib_plankton.database = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:database«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:database« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:database« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:database«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var database;
    (function (database) {
        /**
         */
        function sqlite_make(parameters) {
            var _a;
            return {
                "path": parameters.path,
                "verbose": ((_a = parameters.verbose) !== null && _a !== void 0 ? _a : false),
                "handle": null,
            };
        }
        database.sqlite_make = sqlite_make;
        /**
         */
        function sqlite_init(subject) {
            return __awaiter(this, void 0, void 0, function* () {
                if (subject.handle === null) {
                    yield new Promise((resolve, reject) => {
                        const _nm_sqlite3 = require("sqlite3");
                        subject.handle = new _nm_sqlite3.Database(subject.path, (_nm_sqlite3.OPEN_READWRITE | _nm_sqlite3.OPEN_CREATE | _nm_sqlite3.OPEN_FULLMUTEX), () => { resolve(undefined); });
                    });
                }
                else {
                    // do nothing
                }
                return Promise.resolve(undefined);
            });
        }
        /**
         * @author fenris
         */
        function sqlite_adjust_query(subject, query) {
            if (subject.verbose) {
                console.info(query);
            }
            return {
                "template": query.template,
                "arguments": Object.fromEntries(Object.entries(query.arguments).map(([key, value]) => ([
                    ('$' + key),
                    (((value === null)
                        ||
                            (value === undefined))
                        ? null
                        : ((typeof (value) === 'boolean')
                            ? (value ? '1' : '0')
                            : value.toString()))
                ]))),
            };
        }
        /**
         * @author fenris
         */
        function sqlite_query_free_get(subject, query) {
            return __awaiter(this, void 0, void 0, function* () {
                yield sqlite_init(subject);
                const query_adjusted = sqlite_adjust_query(subject, query);
                return (new Promise((resolve, reject) => {
                    subject.handle.all(query_adjusted.template, query_adjusted.arguments, (error, rows) => {
                        if (error !== null) {
                            reject(error);
                        }
                        else {
                            resolve(rows);
                        }
                    });
                }));
            });
        }
        database.sqlite_query_free_get = sqlite_query_free_get;
        /**
         * @author fenris
         */
        function sqlite_query_free_put(subject, query) {
            return __awaiter(this, void 0, void 0, function* () {
                yield sqlite_init(subject);
                const query_adjusted = sqlite_adjust_query(subject, query);
                return (new Promise((resolve, reject) => {
                    subject.handle.run(query_adjusted.template, query_adjusted.arguments, 
                    // this MUST be an old style function
                    function (error) {
                        if (error) {
                            reject(error);
                        }
                        else {
                            resolve(this["lastID"]);
                        }
                    });
                }));
            });
        }
        database.sqlite_query_free_put = sqlite_query_free_put;
        /**
         * @author fenris
         */
        function sqlite_query_free_set(subject, query) {
            return __awaiter(this, void 0, void 0, function* () {
                yield sqlite_init(subject);
                const query_adjusted = sqlite_adjust_query(subject, query);
                return (new Promise((resolve, reject) => {
                    subject.handle.run(query_adjusted.template, query_adjusted.arguments, 
                    // this MUST be an old style function
                    function (error) {
                        if (error) {
                            reject(error);
                        }
                        else {
                            resolve(this["changes"]);
                        }
                    });
                }));
            });
        }
        database.sqlite_query_free_set = sqlite_query_free_set;
        /**
         */
        function sqlite_formulation_create_table(description_create_table) {
            return database.sql_common_formulation_create_table(description_create_table, {
                "auto_increment_keyword": "AUTOINCREMENT",
                "omit_comments": true,
                "type_map": {
                    "boolean": "INTEGER",
                    "integer": "INTEGER",
                    "string_short": "TEXT",
                    "string_medium": "TEXT",
                    "string_long": "TEXT",
                    "float": "REAL",
                },
            });
        }
        database.sqlite_formulation_create_table = sqlite_formulation_create_table;
        /**
         */
        function sqlite_query_create_table(subject, description) {
            return (sqlite_query_free_set(subject, sqlite_formulation_create_table(description))
                .then(x => Promise.resolve(undefined)));
        }
        database.sqlite_query_create_table = sqlite_query_create_table;
        /**
         */
        function sqlite_formulation_insert(description_insert) {
            return database.sql_common_formulation_insert(description_insert);
        }
        database.sqlite_formulation_insert = sqlite_formulation_insert;
        /**
         */
        function sqlite_query_insert(subject, description_insert) {
            return sqlite_query_free_put(subject, sqlite_formulation_insert(description_insert));
        }
        database.sqlite_query_insert = sqlite_query_insert;
        /**
         */
        function sqlite_formulation_update(description_update) {
            return database.sql_common_formulation_update(description_update);
        }
        database.sqlite_formulation_update = sqlite_formulation_update;
        /**
         */
        function sqlite_query_update(subject, description_update) {
            return sqlite_query_free_set(subject, sqlite_formulation_update(description_update));
        }
        database.sqlite_query_update = sqlite_query_update;
        /**
         */
        function sqlite_formulation_delete(description_delete) {
            return database.sql_common_formulation_delete(description_delete);
        }
        database.sqlite_formulation_delete = sqlite_formulation_delete;
        /**
         */
        function sqlite_query_delete(subject, description_delete) {
            return sqlite_query_free_set(subject, sqlite_formulation_delete(description_delete));
        }
        database.sqlite_query_delete = sqlite_query_delete;
        /**
         */
        function sqlite_formulation_select(description_select) {
            return database.sql_common_formulation_select(description_select);
        }
        database.sqlite_formulation_select = sqlite_formulation_select;
        /**
         */
        function sqlite_query_select(subject, description_select) {
            return sqlite_query_free_get(subject, sqlite_formulation_select(description_select));
        }
        database.sqlite_query_select = sqlite_query_select;
        /**
         */
        function sqlite_database(parameters) {
            const subject = sqlite_make(parameters);
            return {
                "query_free_get": (query) => sqlite_query_free_get(subject, query),
                "query_free_put": (query) => sqlite_query_free_put(subject, query),
                "query_free_set": (query) => sqlite_query_free_set(subject, query),
                "query_create_table": (description_create_table) => sqlite_query_create_table(subject, description_create_table),
                "query_insert": (description_insert) => sqlite_query_insert(subject, description_insert),
                "query_update": (description_update) => sqlite_query_update(subject, description_update),
                "query_delete": (description_delete) => sqlite_query_delete(subject, description_delete),
                "query_select": (description_select) => sqlite_query_select(subject, description_select),
            };
        }
        database.sqlite_database = sqlite_database;
    })(database = lib_plankton.database || (lib_plankton.database = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:database«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:database« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:database« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:database«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var database;
    (function (database) {
        /**
         * @author fenris
         */
        class class_sqlite {
            constructor(parameters) { this.subject = database.sqlite_make(parameters); }
            query_free_get(query) { return database.sqlite_query_free_get(this.subject, query); }
            query_free_put(query) { return database.sqlite_query_free_put(this.subject, query); }
            query_free_set(query) { return database.sqlite_query_free_set(this.subject, query); }
            query_create_table(description_create_table) { return database.sqlite_query_create_table(this.subject, description_create_table); }
            query_insert(description_insert) { return database.sqlite_query_insert(this.subject, description_insert); }
            query_update(description_update) { return database.sqlite_query_update(this.subject, description_update); }
            query_delete(description_delete) { return database.sqlite_query_delete(this.subject, description_delete); }
            query_select(description_select) { return database.sqlite_query_select(this.subject, description_select); }
        }
        database.class_sqlite = class_sqlite;
    })(database = lib_plankton.database || (lib_plankton.database = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:database«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:database« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:database« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:database«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var database;
    (function (database) {
        /**
         */
        function mysql_make(parameters) {
            throw (new Error("not implemented"));
        }
        database.mysql_make = mysql_make;
        /**
         */
        function mysql_init(subject) {
            return __awaiter(this, void 0, void 0, function* () {
                throw (new Error("not implemented"));
            });
        }
        /**
         * @author fenris
         */
        function mysql_adjust_query(subject, query) {
            if (subject.verbose) {
                console.info(query);
            }
            throw (new Error("not implemented"));
        }
        /**
         * @author fenris
         */
        function mysql_query_free_get(subject, query) {
            return __awaiter(this, void 0, void 0, function* () {
                throw (new Error("not implemented"));
            });
        }
        database.mysql_query_free_get = mysql_query_free_get;
        /**
         * @author fenris
         */
        function mysql_query_free_put(subject, query) {
            return __awaiter(this, void 0, void 0, function* () {
                throw (new Error("not implemented"));
            });
        }
        database.mysql_query_free_put = mysql_query_free_put;
        /**
         * @author fenris
         */
        function mysql_query_free_set(subject, query) {
            return __awaiter(this, void 0, void 0, function* () {
                throw (new Error("not implemented"));
            });
        }
        database.mysql_query_free_set = mysql_query_free_set;
        /**
         */
        function mysql_formulation_create_table(description_create_table) {
            return database.sql_common_formulation_create_table(description_create_table, {
                "auto_increment_keyword": "AUTO INCREMENT",
                "omit_comments": false,
                "type_map": {
                    "boolean": "BOOLEAN",
                    "integer": "INTEGER",
                    "string_short": "VARCHAR(63)",
                    "string_medium": "VARCHAR(255)",
                    "string_long": "TEXT",
                    "float": "REAL",
                },
            });
        }
        database.mysql_formulation_create_table = mysql_formulation_create_table;
        /**
         */
        function mysql_query_create_table(subject, description) {
            return (mysql_query_free_set(subject, mysql_formulation_create_table(description))
                .then(x => Promise.resolve(undefined)));
        }
        database.mysql_query_create_table = mysql_query_create_table;
        /**
         */
        function mysql_formulation_insert(description_insert) {
            return database.sql_common_formulation_insert(description_insert);
        }
        database.mysql_formulation_insert = mysql_formulation_insert;
        /**
         */
        function mysql_query_insert(subject, description_insert) {
            return mysql_query_free_put(subject, mysql_formulation_insert(description_insert));
        }
        database.mysql_query_insert = mysql_query_insert;
        /**
         */
        function mysql_formulation_update(description_update) {
            return database.sql_common_formulation_update(description_update);
        }
        database.mysql_formulation_update = mysql_formulation_update;
        /**
         */
        function mysql_query_update(subject, description_update) {
            return mysql_query_free_set(subject, mysql_formulation_update(description_update));
        }
        database.mysql_query_update = mysql_query_update;
        /**
         */
        function mysql_formulation_delete(description_delete) {
            return database.sql_common_formulation_delete(description_delete);
        }
        database.mysql_formulation_delete = mysql_formulation_delete;
        /**
         */
        function mysql_query_delete(subject, description_delete) {
            return mysql_query_free_set(subject, mysql_formulation_delete(description_delete));
        }
        database.mysql_query_delete = mysql_query_delete;
        /**
         */
        function mysql_formulation_select(description_select) {
            return database.sql_common_formulation_select(description_select);
        }
        database.mysql_formulation_select = mysql_formulation_select;
        /**
         */
        function mysql_query_select(subject, description_select) {
            return mysql_query_free_get(subject, mysql_formulation_select(description_select));
        }
        database.mysql_query_select = mysql_query_select;
        /**
         */
        function mysql_database(parameters) {
            const subject = mysql_make(parameters);
            return {
                "query_free_get": (query) => mysql_query_free_get(subject, query),
                "query_free_put": (query) => mysql_query_free_put(subject, query),
                "query_free_set": (query) => mysql_query_free_set(subject, query),
                "query_create_table": (description_create_table) => mysql_query_create_table(subject, description_create_table),
                "query_insert": (description_insert) => mysql_query_insert(subject, description_insert),
                "query_update": (description_update) => mysql_query_update(subject, description_update),
                "query_delete": (description_delete) => mysql_query_delete(subject, description_delete),
                "query_select": (description_select) => mysql_query_select(subject, description_select),
            };
        }
        database.mysql_database = mysql_database;
    })(database = lib_plankton.database || (lib_plankton.database = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:database«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:database« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:database« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:database«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var database;
    (function (database) {
        /**
         * @author fenris
         */
        class class_mysql {
            constructor(parameters) { this.subject = database.mysql_make(parameters); }
            query_free_get(query) { return database.mysql_query_free_get(this.subject, query); }
            query_free_put(query) { return database.mysql_query_free_put(this.subject, query); }
            query_free_set(query) { return database.mysql_query_free_set(this.subject, query); }
            query_create_table(description_create_table) { return database.mysql_query_create_table(this.subject, description_create_table); }
            query_insert(description_insert) { return database.mysql_query_insert(this.subject, description_insert); }
            query_update(description_update) { return database.mysql_query_update(this.subject, description_update); }
            query_delete(description_delete) { return database.mysql_query_delete(this.subject, description_delete); }
            query_select(description_select) { return database.mysql_query_select(this.subject, description_select); }
        }
        database.class_mysql = class_mysql;
    })(database = lib_plankton.database || (lib_plankton.database = {}));
})(lib_plankton || (lib_plankton = {}));
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (g && (g = 0, op[0] && (_ = 0)), _) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
/*
This file is part of »bacterio-plankton:storage«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:storage« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:storage« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:storage«. If not, see <http://www.gnu.org/licenses/>.
 */
/*
This file is part of »bacterio-plankton:storage«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:storage« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:storage« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:storage«. If not, see <http://www.gnu.org/licenses/>.
 */
/*
This file is part of »bacterio-plankton:storage«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:storage« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:storage« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:storage«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var storage;
    (function (storage) {
        var memory;
        (function (memory) {
            /**
             * @author fenris
             */
            function make(parameters) {
                return {
                    "data": {}
                };
            }
            memory.make = make;
            /**
             * @author fenris
             */
            function clear(subject) {
                subject.data = {};
            }
            memory.clear = clear;
            /**
             * @author fenris
             */
            function write(subject, key, value) {
                var exists = (key in subject.data);
                subject.data[key] = value;
                return exists;
            }
            memory.write = write;
            /**
             * @author fenris
             */
            function delete_(subject, key) {
                if (!(key in subject.data)) {
                    throw (new Error("no value for key '" + key + "'"));
                }
                else {
                    delete subject.data[key];
                }
            }
            memory.delete_ = delete_;
            /**
             * @author fenris
             */
            function read(subject, key) {
                if (!(key in subject.data)) {
                    throw (new Error("no value for key '" + key + "'"));
                }
                else {
                    return subject.data[key];
                }
            }
            memory.read = read;
            /**
             * @author fenris
             */
            function list(subject) {
                return Object.keys(subject.data);
            }
            memory.list = list;
            /**
             * @author fenris
             */
            function search(subject, term) {
                return (list(subject)
                    .map(function (key) { return ({ "key": key, "preview": key }); }));
            }
            memory.search = search;
            /**
             * @author fenris
             */
            function implementation_chest(parameters) {
                function wrap(core) {
                    return (new Promise(function (resolve, reject) { resolve(core()); }));
                }
                var subject = make(parameters);
                return {
                    "setup": function (input) { return Promise.resolve(undefined); },
                    "clear": function () { return wrap(function () { return clear(subject); }); },
                    "write": function (key, value) { return wrap(function () { return write(subject, key, value); }); },
                    "delete": function (key) { return wrap(function () { return delete_(subject, key); }); },
                    "read": function (key) { return wrap(function () { return read(subject, key); }); },
                    "search": function (term) { return wrap(function () { return search(subject, term); }); }
                };
            }
            memory.implementation_chest = implementation_chest;
        })(memory = storage.memory || (storage.memory = {}));
    })(storage = lib_plankton.storage || (lib_plankton.storage = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:storage«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:storage« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:storage« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:storage«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var storage;
    (function (storage) {
        var memory;
        (function (memory) {
            /**
             * @author fenris
             */
            var class_chest = /** @class */ (function () {
                function class_chest(parameters) {
                    this.subject = memory.make(parameters);
                }
                class_chest.prototype.setup = function (input) { return Promise.resolve(undefined); };
                class_chest.prototype.clear = function () { memory.clear(this.subject); return Promise.resolve(undefined); };
                class_chest.prototype.write = function (key, value) { return Promise.resolve(memory.write(this.subject, key, value)); };
                class_chest.prototype["delete"] = function (key) { memory.delete_(this.subject, key); return Promise.resolve(undefined); };
                class_chest.prototype.read = function (key) { return Promise.resolve(memory.read(this.subject, key)); };
                class_chest.prototype.search = function (term) { return Promise.resolve(memory.search(this.subject, term)); };
                return class_chest;
            }());
            memory.class_chest = class_chest;
        })(memory = storage.memory || (storage.memory = {}));
    })(storage = lib_plankton.storage || (lib_plankton.storage = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:storage«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:storage« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:storage« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:storage«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var storage;
    (function (storage) {
        var filesystem;
        (function (filesystem) {
            /**
             * @author fenris
             */
            function make(parameters) {
                return {
                    "nodemodule": require("fs")
                };
            }
            filesystem.make = make;
            /**
             */
            function clear(subject) {
                return Promise.reject(new Error("nope"));
            }
            filesystem.clear = clear;
            /**
             * @author fenris
             */
            function write(subject, path, content) {
                return (new Promise(function (resolve, reject) {
                    var exists = subject.nodemodule.existsSync(path);
                    subject.nodemodule.writeFile(path, content, {}, function (error) {
                        if (error === null) {
                            resolve(exists);
                        }
                        else {
                            reject(error);
                        }
                    });
                }));
            }
            filesystem.write = write;
            /**
             * @author fenris
             */
            function delete_(subject, path) {
                return (new Promise(function (resolve, reject) {
                    subject.nodemodule.unlink(path, function (error) {
                        if (error === null) {
                            resolve(undefined);
                        }
                        else {
                            reject(error);
                        }
                    });
                }));
            }
            filesystem.delete_ = delete_;
            /**
             * @author fenris
             */
            function read(subject, path) {
                return (new Promise(function (resolve, reject) {
                    subject.nodemodule.readFile(path, {}, function (error, content) {
                        if (error === null) {
                            resolve(content);
                        }
                        else {
                            reject(error);
                        }
                    });
                }));
            }
            filesystem.read = read;
            /**
             */
            function implementation_chest(parameters) {
                var subject = make(parameters);
                return {
                    "setup": function (input) { return Promise.resolve(undefined); },
                    "clear": function () { return clear(subject); },
                    "write": function (key, value) { return write(subject, key, value); },
                    "delete": function (key) { return delete_(subject, key); },
                    "read": function (key) { return read(subject, key); },
                    "search": function (term) { return Promise.reject("not available"); }
                };
            }
            filesystem.implementation_chest = implementation_chest;
        })(filesystem = storage.filesystem || (storage.filesystem = {}));
    })(storage = lib_plankton.storage || (lib_plankton.storage = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:storage«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:storage« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:storage« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:storage«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var storage;
    (function (storage) {
        var filesystem;
        (function (filesystem) {
            /**
             * @author fenris
             */
            var class_chest = /** @class */ (function () {
                function class_chest(parameters) {
                    this.subject = filesystem.make(parameters);
                }
                class_chest.prototype.setup = function (input) { return Promise.resolve(undefined); };
                class_chest.prototype.clear = function () { return filesystem.clear(this.subject); };
                class_chest.prototype.write = function (key, value) { return filesystem.write(this.subject, key, value); };
                class_chest.prototype["delete"] = function (key) { return filesystem.delete_(this.subject, key); };
                class_chest.prototype.read = function (key) { return filesystem.read(this.subject, key); };
                class_chest.prototype.search = function (searchterm) { return Promise.reject(new Error("not available")); };
                return class_chest;
            }());
            filesystem.class_chest = class_chest;
        })(filesystem = storage.filesystem || (storage.filesystem = {}));
    })(storage = lib_plankton.storage || (lib_plankton.storage = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:storage«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:storage« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:storage« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:storage«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var storage;
    (function (storage) {
        /**
         */
        function sql_table_autokey_make(parameters) {
            return {
                "database_implementation": parameters.database_implementation,
                "table_name": parameters.table_name,
                "key_name": parameters.key_name
            };
        }
        storage.sql_table_autokey_make = sql_table_autokey_make;
        /**
         */
        function sql_table_autokey_setup(subject, description_create_table) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, subject.database_implementation.query_create_table(description_create_table)];
                });
            });
        }
        storage.sql_table_autokey_setup = sql_table_autokey_setup;
        /**
         */
        function sql_table_autokey_create(subject, value) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, subject.database_implementation.query_insert({
                            "table_name": subject.table_name,
                            "values": value
                        })];
                });
            });
        }
        storage.sql_table_autokey_create = sql_table_autokey_create;
        /**
         */
        function sql_table_autokey_update(subject, key, value) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    return [2 /*return*/, (subject.database_implementation.query_update({
                            "table_name": subject.table_name,
                            "values": value,
                            "condition": lib_plankton.string.coin("`{{key_name}}` = $key", {
                                "key_name": subject.key_name
                            }),
                            "arguments": {
                                "key": key
                            }
                        })
                            .then(function (x) { return Promise.resolve(undefined); }))];
                });
            });
        }
        storage.sql_table_autokey_update = sql_table_autokey_update;
        /**
         */
        function sql_table_autokey_delete(subject, key) {
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0: return [4 /*yield*/, subject.database_implementation.query_delete({
                                "table_name": subject.table_name,
                                "condition": lib_plankton.string.coin("`{{key_name}}` = $key", {
                                    "key_name": subject.key_name
                                }),
                                "arguments": {
                                    "key": key
                                }
                            })];
                        case 1:
                            _a.sent();
                            return [2 /*return*/, Promise.resolve(undefined)];
                    }
                });
            });
        }
        storage.sql_table_autokey_delete = sql_table_autokey_delete;
        /**
         */
        function sql_table_autokey_read(subject, key) {
            return __awaiter(this, void 0, void 0, function () {
                var rows;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0: return [4 /*yield*/, subject.database_implementation.query_select({
                                "source": subject.table_name,
                                "fields": null,
                                "condition": lib_plankton.string.coin("`{{key_name}}` = $key", {
                                    "key_name": subject.key_name
                                }),
                                "arguments": {
                                    "key": key
                                }
                            })];
                        case 1:
                            rows = _a.sent();
                            if (rows.length < 1) {
                                return [2 /*return*/, Promise.reject("not found")];
                            }
                            else if (rows.length > 1) {
                                return [2 /*return*/, Promise.reject("ambiguous")];
                            }
                            else {
                                delete rows[0][subject.key_name];
                                return [2 /*return*/, Promise.resolve(rows[0])];
                            }
                            return [2 /*return*/];
                    }
                });
            });
        }
        storage.sql_table_autokey_read = sql_table_autokey_read;
        /**
         * @todo correct preview
         */
        function sql_table_autokey_search(subject, term) {
            return __awaiter(this, void 0, void 0, function () {
                var rows;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0: return [4 /*yield*/, subject.database_implementation.query_select({
                                "source": subject.table_name,
                                "fields": null,
                                "condition": ((term === null) ? null : term.expression),
                                "arguments": ((term === null) ? null : term.arguments)
                            })];
                        case 1:
                            rows = _a.sent();
                            return [2 /*return*/, Promise.resolve(rows
                                    .map(function (row) { return ({
                                    "key": row[subject.key_name],
                                    "preview": row
                                }); }))];
                    }
                });
            });
        }
        storage.sql_table_autokey_search = sql_table_autokey_search;
        /**
         */
        function sql_table_autokey_store(parameters) {
            var subject = sql_table_autokey_make(parameters);
            return {
                "setup": function (input) { return sql_table_autokey_setup(subject, input); },
                "create": function (value) { return sql_table_autokey_create(subject, value); },
                "update": function (key, value) { return sql_table_autokey_update(subject, key, value); },
                "delete": function (key) { return sql_table_autokey_delete(subject, key); },
                "read": function (key) { return sql_table_autokey_read(subject, key); },
                "search": function (term) { return sql_table_autokey_search(subject, term); }
            };
        }
        storage.sql_table_autokey_store = sql_table_autokey_store;
    })(storage = lib_plankton.storage || (lib_plankton.storage = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:storage«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:storage« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:storage« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:storage«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var storage;
    (function (storage) {
        /**
         * @author fenris
         */
        var class_sql_table_autokey = /** @class */ (function () {
            function class_sql_table_autokey(parameters) {
                this.subject = storage.sql_table_autokey_make(parameters);
            }
            class_sql_table_autokey.prototype.setup = function (input) { return storage.sql_table_autokey_setup(this.subject, input); };
            class_sql_table_autokey.prototype.create = function (value) { return storage.sql_table_autokey_create(this.subject, value); };
            class_sql_table_autokey.prototype.update = function (key, value) { return storage.sql_table_autokey_update(this.subject, key, value); };
            class_sql_table_autokey.prototype["delete"] = function (key) { return storage.sql_table_autokey_delete(this.subject, key); };
            class_sql_table_autokey.prototype.read = function (key) { return storage.sql_table_autokey_read(this.subject, key); };
            class_sql_table_autokey.prototype.search = function (term) { return storage.sql_table_autokey_search(this.subject, term); };
            return class_sql_table_autokey;
        }());
        storage.class_sql_table_autokey = class_sql_table_autokey;
    })(storage = lib_plankton.storage || (lib_plankton.storage = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:storage«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:storage« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:storage« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:storage«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var storage;
    (function (storage) {
        var sql_table_common;
        (function (sql_table_common) {
            /**
             */
            function make(parameters) {
                return {
                    "database_implementation": parameters.database_implementation,
                    "table_name": parameters.table_name,
                    "key_names": parameters.key_names
                };
            }
            sql_table_common.make = make;
            /**
             */
            function key_condition(subject, key) {
                return {
                    "condition": lib_string.coin("({{clauses}})", {
                        "clauses": (subject.key_names
                            .map(function (key_name) { return lib_plankton.string.coin("(`{{name}}` = $key_{{name}})", {
                            "name": key_name
                        }); })
                            .join(" AND "))
                    }),
                    "arguments": Object.fromEntries(subject.key_names
                        .map(function (key_name, index) { return ([
                        lib_plankton.string.coin("key_{{name}}", {
                            "name": key_name
                        }),
                        key[index]
                    ]); }))
                };
            }
            /**
             */
            function setup(subject, description_create_table) {
                return __awaiter(this, void 0, void 0, function () {
                    return __generator(this, function (_a) {
                        return [2 /*return*/, subject.database_implementation.query_create_table(description_create_table)];
                    });
                });
            }
            sql_table_common.setup = setup;
            /**
             */
            function clear(subject) {
                return __awaiter(this, void 0, void 0, function () {
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0: return [4 /*yield*/, subject.database_implementation.query_delete({
                                    "table_name": subject.table_name,
                                    "condition": "TRUE",
                                    "arguments": {}
                                })];
                            case 1:
                                _a.sent();
                                return [2 /*return*/, Promise.resolve(undefined)];
                        }
                    });
                });
            }
            sql_table_common.clear = clear;
            /**
             * @todo optimize: avoid read
             */
            function write(subject, key, value) {
                return __awaiter(this, void 0, void 0, function () {
                    var exists, error_1, field_names, condition;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                _a.trys.push([0, 2, , 3]);
                                return [4 /*yield*/, read(subject, key)];
                            case 1:
                                _a.sent();
                                exists = true;
                                return [3 /*break*/, 3];
                            case 2:
                                error_1 = _a.sent();
                                exists = false;
                                return [3 /*break*/, 3];
                            case 3:
                                field_names = Object.keys(value);
                                if (!!exists) return [3 /*break*/, 5];
                                return [4 /*yield*/, subject.database_implementation.query_insert({
                                        "table_name": subject.table_name,
                                        "values": Object.assign(
                                        // key
                                        Object.fromEntries(subject.key_names.map(function (key_name, index) { return ([key_name, key[index]]); })), 
                                        // value
                                        value)
                                    })];
                            case 4:
                                _a.sent();
                                return [3 /*break*/, 7];
                            case 5:
                                condition = key_condition(subject, key);
                                return [4 /*yield*/, subject.database_implementation.query_update({
                                        "table_name": subject.table_name,
                                        "values": value,
                                        "condition": condition.condition,
                                        "arguments": condition.arguments
                                    })];
                            case 6:
                                _a.sent();
                                _a.label = 7;
                            case 7: return [2 /*return*/, Promise.resolve(exists)];
                        }
                    });
                });
            }
            sql_table_common.write = write;
            /**
             */
            function delete_(subject, key) {
                return __awaiter(this, void 0, void 0, function () {
                    var condition;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                condition = key_condition(subject, key);
                                return [4 /*yield*/, subject.database_implementation.query_delete({
                                        "table_name": subject.table_name,
                                        "condition": condition.condition,
                                        "arguments": condition.arguments
                                    })];
                            case 1:
                                _a.sent();
                                return [2 /*return*/, Promise.resolve(undefined)];
                        }
                    });
                });
            }
            sql_table_common.delete_ = delete_;
            /**
             */
            function read(subject, key) {
                return __awaiter(this, void 0, void 0, function () {
                    var condition, rows;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                condition = key_condition(subject, key);
                                return [4 /*yield*/, subject.database_implementation.query_select({
                                        "source": subject.table_name,
                                        "fields": null,
                                        "condition": condition.condition,
                                        "arguments": condition.arguments
                                    })];
                            case 1:
                                rows = _a.sent();
                                if (rows.length < 1) {
                                    return [2 /*return*/, Promise.reject("not found")];
                                }
                                else if (rows.length > 1) {
                                    return [2 /*return*/, Promise.reject("ambiguous")];
                                }
                                else {
                                    subject.key_names.forEach(function (key_name) { delete rows[0][key_name]; });
                                    return [2 /*return*/, Promise.resolve(rows[0])];
                                }
                                return [2 /*return*/];
                        }
                    });
                });
            }
            sql_table_common.read = read;
            /**
             * @todo correct preview
             */
            function search(subject, term) {
                return __awaiter(this, void 0, void 0, function () {
                    var rows;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0: return [4 /*yield*/, subject.database_implementation.query_select({
                                    "source": subject.table_name,
                                    "fields": null,
                                    "condition": ((term === null) ? null : term.expression),
                                    "arguments": ((term === null) ? null : term.arguments)
                                })];
                            case 1:
                                rows = _a.sent();
                                return [2 /*return*/, Promise.resolve(rows
                                        .map(function (row) { return ({
                                        "key": subject.key_names.map(function (name) { return row[name]; }),
                                        "preview": row
                                    }); }))];
                        }
                    });
                });
            }
            sql_table_common.search = search;
            /**
             */
            function chest(parameters) {
                var subject = make(parameters);
                return {
                    "setup": function (input) { return setup(subject, input); },
                    "clear": function () { return clear(subject); },
                    "write": function (key, value) { return write(subject, key, value); },
                    "delete": function (key) { return delete_(subject, key); },
                    "read": function (key) { return read(subject, key); },
                    "search": function (term) { return search(subject, term); }
                };
            }
            sql_table_common.chest = chest;
        })(sql_table_common = storage.sql_table_common || (storage.sql_table_common = {}));
    })(storage = lib_plankton.storage || (lib_plankton.storage = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:storage«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:storage« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:storage« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:storage«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var storage;
    (function (storage) {
        var sql_table_common;
        (function (sql_table_common) {
            /**
             * @author fenris
             */
            var class_chest = /** @class */ (function () {
                function class_chest(parameters) {
                    this.subject = sql_table_common.make(parameters);
                }
                class_chest.prototype.setup = function (input) { return sql_table_common.setup(this.subject, input); };
                class_chest.prototype.clear = function () { return sql_table_common.clear(this.subject); };
                class_chest.prototype.write = function (key, value) { return sql_table_common.write(this.subject, key, value); };
                class_chest.prototype["delete"] = function (key) { return sql_table_common.delete_(this.subject, key); };
                class_chest.prototype.read = function (key) { return sql_table_common.read(this.subject, key); };
                class_chest.prototype.search = function (term) { return sql_table_common.search(this.subject, term); };
                return class_chest;
            }());
            sql_table_common.class_chest = class_chest;
        })(sql_table_common = storage.sql_table_common || (storage.sql_table_common = {}));
    })(storage = lib_plankton.storage || (lib_plankton.storage = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:shape«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:shape« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:shape« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:shape«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var shape;
    (function (shape_1) {
        /**
         * @author fenris
         */
        function inspection_create() {
            return {
                "flaws": [],
                "sub": []
            };
        }
        shape_1.inspection_create = inspection_create;
        /**
         * @author fenris
         */
        function inspection_add(main, flaw) {
            main.flaws.push(flaw);
        }
        shape_1.inspection_add = inspection_add;
        /**
         * @author fenris
         */
        function inspection_extend(main, prefix, sub) {
            if ((sub.flaws.length <= 0)
                &&
                    (sub.sub.length <= 0)) {
                // do nothing
            }
            else {
                main.sub.push({ "position": prefix, "inspection": sub });
            }
        }
        shape_1.inspection_extend = inspection_extend;
        /**
         */
        function inspection_flatten(inspection) {
            return (inspection.flaws
                .concat(inspection.sub
                .map((entry) => (inspection_flatten(entry.inspection)
                .map(rest => lib_plankton.string.coin("[{{position}}] {{rest}}", {
                "position": entry.position,
                "rest": rest
            }))))
                .reduce((x, y) => x.concat(y), [])));
        }
        /**
         */
        var _pool = {};
        /**
         * @todo cache
         */
        function construct(shape) {
            return _pool[shape.kind].construct(shape.parameters);
        }
        /**
         */
        function get_logic(shape) {
            if (!(shape.kind in _pool)) {
                throw (new Error("missing shape: " + shape.kind));
            }
            else {
                return _pool[shape.kind].logic(construct(shape));
            }
        }
        /**
         */
        function inspect(shape, value) {
            return get_logic(shape).inspect(inspect, value);
        }
        shape_1.inspect = inspect;
        /**
         */
        function inspect_flat(shape, value) {
            return inspection_flatten(inspect(shape, value));
        }
        shape_1.inspect_flat = inspect_flat;
        /**
         */
        function show(shape) {
            return get_logic(shape).show(show);
        }
        shape_1.show = show;
        /**
         */
        function to_typescript_type(shape) {
            return get_logic(shape).to_typescript_type(to_typescript_type);
        }
        shape_1.to_typescript_type = to_typescript_type;
        /**
         */
        function to_jsonschema(shape) {
            return get_logic(shape).to_jsonschema(to_jsonschema);
        }
        shape_1.to_jsonschema = to_jsonschema;
        /**
         */
        function to_oas_schema(shape) {
            return get_logic(shape).to_oas_schema(to_oas_schema);
        }
        shape_1.to_oas_schema = to_oas_schema;
        /**
         */
        function example(shape) {
            return get_logic(shape).example(example);
        }
        shape_1.example = example;
        /**
         */
        function register(name, construct, logic) {
            _pool[name] = {
                "construct": construct,
                "logic": logic,
            };
        }
        shape_1.register = register;
    })(shape = lib_plankton.shape || (lib_plankton.shape = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:shape«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:shape« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:shape« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:shape«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var shape;
    (function (shape_2) {
        var any;
        (function (any) {
            /**
             */
            function make(options = {}) {
                return {};
            }
            any.make = make;
            /**
             */
            function inspect(sub_inspect, subject, value) {
                let inspection = shape_2.inspection_create();
                return inspection;
            }
            /**
             */
            function show(sub_show, subject) {
                return "any";
            }
            /**
             */
            function to_typescript_type(sub_to_typescript_type, subject) {
                return "any";
            }
            /**
             */
            function to_jsonschema(sub_to_jsonschema, subject) {
                return {};
            }
            /**
             */
            function example(sub_example, subject) {
                return null;
            }
            shape_2.register("any", (parameters) => make({}), (subject) => ({
                "inspect": (sub_inspect, value) => inspect(sub_inspect, subject, value),
                "show": (sub_show) => show(sub_show, subject),
                "to_typescript_type": (sub_to_typescript_type) => to_typescript_type(sub_to_typescript_type, subject),
                "to_jsonschema": (sub_to_jsonschema) => to_jsonschema(sub_to_jsonschema, subject),
                "to_oas_schema": (sub_to_oas_schema) => to_jsonschema(sub_to_oas_schema, subject),
                "example": (sub_example) => example(sub_example, subject),
            }));
        })(any = shape_2.any || (shape_2.any = {}));
    })(shape = lib_plankton.shape || (lib_plankton.shape = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:shape«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:shape« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:shape« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:shape«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var shape;
    (function (shape_3) {
        var null_;
        (function (null_) {
            /**
             */
            function make(options = {}) {
                return {};
            }
            null_.make = make;
            /**
             */
            function inspect(sub_inspect, subject, value) {
                let inspection = shape_3.inspection_create();
                if (!(value === null)) {
                    shape_3.inspection_add(inspection, "null expected");
                }
                else {
                    // all good
                }
                return inspection;
            }
            /**
             */
            function show(sub_show, subject) {
                return "null";
            }
            /**
             */
            function to_typescript_type(sub_to_typescript_type, subject) {
                return "null";
            }
            /**
             */
            function to_jsonschema(sub_to_jsonschema, subject) {
                return {
                    "type": "null",
                };
            }
            /**
             */
            function example(sub_example, subject) {
                return null;
            }
            shape_3.register("null", (parameters) => make({}), (subject) => ({
                "inspect": (sub_inspect, value) => inspect(sub_inspect, subject, value),
                "show": (sub_show) => show(sub_show, subject),
                "to_typescript_type": (sub_to_typescript_type) => to_typescript_type(sub_to_typescript_type, subject),
                "to_jsonschema": (sub_to_jsonschema) => to_jsonschema(sub_to_jsonschema, subject),
                "to_oas_schema": (sub_to_oas_schema) => to_jsonschema(sub_to_oas_schema, subject),
                "example": (sub_example) => example(sub_example, subject),
            }));
        })(null_ = shape_3.null_ || (shape_3.null_ = {}));
    })(shape = lib_plankton.shape || (lib_plankton.shape = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:shape«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:shape« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:shape« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:shape«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var shape;
    (function (shape_4) {
        var boolean;
        (function (boolean) {
            /**
             */
            function make(options = {}) {
                options = Object.assign({
                    "soft": false,
                    "defaultvalue": undefined,
                    "description": undefined,
                }, options);
                return {
                    "soft": options.soft,
                    "defaultvalue": ((options.defaultvalue === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.defaultvalue)),
                    "description": ((options.description === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.description)),
                };
            }
            boolean.make = make;
            /**
             */
            function inspect(sub_inspect, subject, value) {
                let inspection = shape_4.inspection_create();
                if (value === null) {
                    if (subject.soft) {
                        // all good
                    }
                    else {
                        shape_4.inspection_add(inspection, "null is not allowed");
                    }
                }
                else {
                    const jstype_actual = typeof (value);
                    const jstype_expected = "boolean";
                    if (jstype_actual === jstype_expected) {
                        // all good
                    }
                    else {
                        shape_4.inspection_add(inspection, lib_plankton.string.coin("expected JS-type '{{expected}}' but got '{{actual}}'", {
                            "expected": jstype_expected,
                            "actual": jstype_actual,
                        }));
                    }
                }
                return inspection;
            }
            /**
             */
            function show(sub_show, subject) {
                const core = "boolean";
                return (subject.soft ? ("~" + core) : core);
            }
            /**
             */
            function to_typescript_type(sub_to_typescript_type, subject) {
                const core = "boolean";
                return (subject.soft ? ("(null | " + core + ")") : core);
            }
            /**
             */
            function to_jsonschema(sub_to_jsonschema, subject) {
                const common = {
                    "description": lib_plankton.pod.distinguish(subject.description, () => undefined, x => x),
                    "default": lib_plankton.pod.distinguish(subject.defaultvalue, () => undefined, x => x),
                };
                const core = {
                    "type": "boolean",
                };
                return (subject.soft
                    ? {
                        "anyOf": [
                            Object.assign({ "type": "null" }, common),
                            Object.assign(core, common),
                        ],
                    }
                    : core);
            }
            /**
             */
            function example(sub_example, subject) {
                return (subject.soft ? null : false);
            }
            shape_4.register("boolean", (parameters) => make({
                "soft": parameters.soft,
                "description": parameters.description,
                "defaultvalue": parameters.defaultvalue,
            }), (subject) => ({
                "inspect": (sub_inspect, value) => inspect(sub_inspect, subject, value),
                "show": (sub_show) => show(sub_show, subject),
                "to_typescript_type": (sub_to_typescript_type) => to_typescript_type(sub_to_typescript_type, subject),
                "to_jsonschema": (sub_to_jsonschema) => to_jsonschema(sub_to_jsonschema, subject),
                "to_oas_schema": (sub_to_oas_schema) => to_jsonschema(sub_to_oas_schema, subject),
                "example": (sub_example) => example(sub_example, subject),
            }));
        })(boolean = shape_4.boolean || (shape_4.boolean = {}));
    })(shape = lib_plankton.shape || (lib_plankton.shape = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:shape«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:shape« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:shape« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:shape«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var shape;
    (function (shape_5) {
        var integer;
        (function (integer) {
            /**
             */
            function make(options = {}) {
                options = Object.assign({
                    "soft": false,
                    "defaultvalue": undefined,
                    "description": undefined,
                    "minimum": undefined,
                    "maximum": undefined,
                }, options);
                return {
                    "soft": options.soft,
                    "defaultvalue": ((options.defaultvalue === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.defaultvalue)),
                    "description": ((options.description === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.description)),
                    "minimum": ((options.minimum === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.minimum)),
                    "maximum": ((options.minimum === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.maximum)),
                };
            }
            integer.make = make;
            /**
             */
            function inspect(sub_inspect, subject, value) {
                let inspection = shape_5.inspection_create();
                if (value === null) {
                    if (subject.soft) {
                        // all good
                    }
                    else {
                        shape_5.inspection_add(inspection, "null is not allowed");
                    }
                }
                else {
                    const jstype_actual = typeof (value);
                    const jstype_expected = "number";
                    if (!(jstype_actual === jstype_expected)) {
                        shape_5.inspection_add(inspection, lib_plankton.string.coin("expected JS-type '{{expected}}' but got '{{actual}}'", {
                            "expected": jstype_expected,
                            "actual": jstype_actual,
                        }));
                    }
                    else {
                        if (isNaN(parseInt(value))) {
                            shape_5.inspection_add(inspection, "value is not parsable to a valid int");
                        }
                        else {
                            // minimum
                            {
                                if (!lib_plankton.pod.distinguish(subject.minimum, () => true, x => (value >= x))) {
                                    shape_5.inspection_add(inspection, lib_plankton.string.coin("value is below the minimum of '{{minimum}}'", {
                                        "minimum": lib_plankton.pod.cull(subject.minimum).toFixed(0),
                                    }));
                                }
                                else {
                                    // do nothing
                                }
                            }
                            // maximum
                            {
                                if (!lib_plankton.pod.distinguish(subject.maximum, () => true, x => (value <= x))) {
                                    shape_5.inspection_add(inspection, lib_plankton.string.coin("value is beyond the maximum of '{{maximum}}'", {
                                        "maximum": lib_plankton.pod.cull(subject.maximum).toFixed(0),
                                    }));
                                }
                                else {
                                    // do nothing
                                }
                            }
                        }
                    }
                }
                return inspection;
            }
            /**
             */
            function show(sub_show, subject) {
                const core = "integer";
                return (subject.soft ? ("~" + core) : core);
            }
            /**
             */
            function to_typescript_type(sub_to_typescript_type, subject) {
                const core = "number";
                return (subject.soft ? ("(null | " + core + ")") : core);
            }
            /**
             */
            function to_jsonschema(sub_to_jsonschema, subject) {
                const common = {
                    "description": lib_plankton.pod.distinguish(subject.description, () => undefined, x => x),
                    "default": lib_plankton.pod.distinguish(subject.defaultvalue, () => undefined, x => x),
                };
                const core = {
                    "type": "integer",
                    "minimum": lib_plankton.pod.distinguish(subject.minimum, () => undefined, x => x),
                    "maximum": lib_plankton.pod.distinguish(subject.maximum, () => undefined, x => x),
                };
                return (subject.soft
                    ? {
                        "anyOf": [
                            Object.assign({ "type": "null" }, common),
                            Object.assign(core, common),
                        ],
                    }
                    : core);
            }
            /**
             */
            function example(sub_example, subject) {
                return (subject.soft ? null : 0);
            }
            shape_5.register("integer", (parameters) => make({
                "soft": parameters.soft,
                "description": parameters.description,
                "defaultvalue": parameters.defaultvalue,
                "minimum": parameters.minimum,
                "maximum": parameters.maximum,
            }), (subject) => ({
                "inspect": (sub_inspect, value) => inspect(sub_inspect, subject, value),
                "show": (sub_show) => show(sub_show, subject),
                "to_typescript_type": (sub_to_typescript_type) => to_typescript_type(sub_to_typescript_type, subject),
                "to_jsonschema": (sub_to_jsonschema) => to_jsonschema(sub_to_jsonschema, subject),
                "to_oas_schema": (sub_to_oas_schema) => to_jsonschema(sub_to_oas_schema, subject),
                "example": (sub_example) => example(sub_example, subject),
            }));
        })(integer = shape_5.integer || (shape_5.integer = {}));
    })(shape = lib_plankton.shape || (lib_plankton.shape = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:shape«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:shape« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:shape« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:shape«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var shape;
    (function (shape_6) {
        var float;
        (function (float) {
            /**
             */
            function make(options = {}) {
                options = Object.assign({
                    "soft": false,
                    "defaultvalue": undefined,
                    "description": undefined,
                    "minimum": undefined,
                    "maximum": undefined,
                }, options);
                return {
                    "soft": options.soft,
                    "defaultvalue": ((options.defaultvalue === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.defaultvalue)),
                    "description": ((options.description === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.description)),
                    "minimum": ((options.minimum === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.minimum)),
                    "maximum": ((options.minimum === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.maximum)),
                };
            }
            float.make = make;
            /**
             */
            function inspect(sub_inspect, subject, value) {
                let inspection = shape_6.inspection_create();
                if (value === null) {
                    if (subject.soft) {
                        // all good
                    }
                    else {
                        shape_6.inspection_add(inspection, "null is not allowed");
                    }
                }
                else {
                    const jstype_actual = typeof (value);
                    const jstype_expected = "number";
                    if (!(jstype_actual === jstype_expected)) {
                        shape_6.inspection_add(inspection, lib_plankton.string.coin("expected JS-type '{{expected}}' but got '{{actual}}'", {
                            "expected": jstype_expected,
                            "actual": jstype_actual,
                        }));
                    }
                    else {
                        if (isNaN(parseInt(value))) {
                            shape_6.inspection_add(inspection, "value is not parsable to a valid float");
                        }
                        else {
                            // minimum
                            {
                                if (!lib_plankton.pod.distinguish(subject.minimum, () => true, x => (value >= x))) {
                                    shape_6.inspection_add(inspection, lib_plankton.string.coin("value is below the minimum of '{{minimum}}'", {
                                        "minimum": lib_plankton.pod.cull(subject.minimum).toFixed(0),
                                    }));
                                }
                                else {
                                    // do nothing
                                }
                            }
                            // maximum
                            {
                                if (!lib_plankton.pod.distinguish(subject.maximum, () => true, x => (value <= x))) {
                                    shape_6.inspection_add(inspection, lib_plankton.string.coin("value is beyond the maximum of '{{maximum}}'", {
                                        "maximum": lib_plankton.pod.cull(subject.maximum).toFixed(0),
                                    }));
                                }
                                else {
                                    // do nothing
                                }
                            }
                        }
                    }
                }
                return inspection;
            }
            /**
             */
            function show(sub_show, subject) {
                const core = "float";
                return (subject.soft ? ("~" + core) : core);
            }
            /**
             */
            function to_typescript_type(sub_to_typescript_type, subject) {
                const core = "number";
                return (subject.soft ? ("(null | " + core + ")") : core);
            }
            /**
             */
            function to_jsonschema(sub_to_jsonschema, subject) {
                const common = {
                    "description": lib_plankton.pod.distinguish(subject.description, () => undefined, x => x),
                    "default": lib_plankton.pod.distinguish(subject.defaultvalue, () => undefined, x => x),
                };
                const core = {
                    "type": "float",
                    "minimum": lib_plankton.pod.distinguish(subject.minimum, () => undefined, x => x),
                    "maximum": lib_plankton.pod.distinguish(subject.maximum, () => undefined, x => x),
                };
                return (subject.soft
                    ? {
                        "anyOf": [
                            Object.assign({ "type": "null" }, common),
                            Object.assign(core, common),
                        ],
                    }
                    : core);
            }
            /**
             */
            function example(sub_example, subject) {
                return (subject.soft ? null : 0);
            }
            shape_6.register("float", (parameters) => make({
                "soft": parameters.soft,
                "description": parameters.description,
                "defaultvalue": parameters.defaultvalue,
                "minimum": parameters.minimum,
                "maximum": parameters.maximum,
            }), (subject) => ({
                "inspect": (sub_inspect, value) => inspect(sub_inspect, subject, value),
                "show": (sub_show) => show(sub_show, subject),
                "to_typescript_type": (sub_to_typescript_type) => to_typescript_type(sub_to_typescript_type, subject),
                "to_jsonschema": (sub_to_jsonschema) => to_jsonschema(sub_to_jsonschema, subject),
                "to_oas_schema": (sub_to_oas_schema) => to_jsonschema(sub_to_oas_schema, subject),
                "example": (sub_example) => example(sub_example, subject),
            }));
        })(float = shape_6.float || (shape_6.float = {}));
    })(shape = lib_plankton.shape || (lib_plankton.shape = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:shape«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:shape« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:shape« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:shape«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var shape;
    (function (shape_7) {
        var string;
        (function (string) {
            /**
             */
            function make(options = {}) {
                options = Object.assign({
                    "soft": false,
                    "defaultvalue": undefined,
                    "description": undefined,
                    "pattern": undefined,
                    "min_length": undefined,
                    "max_lenth": undefined,
                }, options);
                return {
                    "soft": options.soft,
                    "defaultvalue": ((options.defaultvalue === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.defaultvalue)),
                    "description": ((options.description === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.description)),
                    "pattern": ((options.pattern === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.pattern)),
                    "min_length": ((options.min_length === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.min_length)),
                    "max_length": ((options.max_length === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.max_length)),
                };
            }
            string.make = make;
            /**
             */
            function inspect(sub_inspect, subject, value) {
                let inspection = shape_7.inspection_create();
                if (value === null) {
                    if (subject.soft) {
                        // all good
                    }
                    else {
                        shape_7.inspection_add(inspection, "null is not allowed");
                    }
                }
                else {
                    const jstype_actual = typeof (value);
                    const jstype_expected = "string";
                    if (!(jstype_actual === jstype_expected)) {
                        shape_7.inspection_add(inspection, lib_plankton.string.coin("expected JS-type '{{expected}}' but got '{{actual}}'", {
                            "expected": jstype_expected,
                            "actual": jstype_actual,
                        }));
                    }
                    else {
                        const value_ = value;
                        // pattern
                        {
                            if (!lib_plankton.pod.distinguish(subject.pattern, () => true, x => (new RegExp(x)).test(value_))) {
                                shape_7.inspection_add(inspection, lib_plankton.string.coin("string does not match the pattern '{{pattern}}'", {
                                    "pattern": lib_plankton.pod.cull(subject.pattern),
                                }));
                            }
                            else {
                                // do nothing
                            }
                        }
                        // min_length
                        {
                            if (!lib_plankton.pod.distinguish(subject.min_length, () => true, x => (value_.length >= x))) {
                                shape_7.inspection_add(inspection, lib_plankton.string.coin("string is shorter than '{{min_length}}'", {
                                    "min_length": lib_plankton.pod.cull(subject.min_length).toFixed(0),
                                }));
                            }
                            else {
                                // do nothing
                            }
                        }
                        // max_length
                        {
                            if (!lib_plankton.pod.distinguish(subject.max_length, () => true, x => (value_.length <= x))) {
                                shape_7.inspection_add(inspection, lib_plankton.string.coin("string is longer than '{{max_length}}'", {
                                    "min_length": lib_plankton.pod.cull(subject.max_length).toFixed(0),
                                }));
                            }
                            else {
                                // do nothing
                            }
                        }
                    }
                }
                return inspection;
            }
            /**
             */
            function show(sub_show, subject) {
                const core = "string";
                return (subject.soft ? ("~" + core) : core);
            }
            /**
             */
            function to_typescript_type(sub_to_typescript_type, subject) {
                const core = "string";
                return (subject.soft ? ("(null | " + core + ")") : core);
            }
            /**
             */
            function to_jsonschema(sub_to_jsonschema, subject) {
                const common = {
                    "description": lib_plankton.pod.distinguish(subject.description, () => undefined, x => x),
                    "default": lib_plankton.pod.distinguish(subject.defaultvalue, () => undefined, x => x),
                };
                const core = {
                    "type": "string",
                    // TODO: transform?
                    "pattern": lib_plankton.pod.distinguish(subject.pattern, () => undefined, x => x),
                    "minLength": lib_plankton.pod.distinguish(subject.min_length, () => undefined, x => x),
                    "maxLenth": lib_plankton.pod.distinguish(subject.max_length, () => undefined, x => x),
                };
                return (subject.soft
                    ? {
                        "anyOf": [
                            Object.assign({ "type": "null" }, common),
                            Object.assign(core, common),
                        ],
                    }
                    : core);
            }
            /**
             */
            function example(sub_example, subject) {
                return (subject.soft ? null : "");
            }
            shape_7.register("string", (parameters) => make({
                "soft": parameters.soft,
                "description": parameters.description,
                "defaultvalue": parameters.defaultvalue,
                "pattern": parameters.pattern,
                "min_length": parameters.min_length,
                "max_length": parameters.max_length,
            }), (subject) => ({
                "inspect": (sub_inspect, value) => inspect(sub_inspect, subject, value),
                "show": (sub_show) => show(sub_show, subject),
                "to_typescript_type": (sub_to_typescript_type) => to_typescript_type(sub_to_typescript_type, subject),
                "to_jsonschema": (sub_to_jsonschema) => to_jsonschema(sub_to_jsonschema, subject),
                "to_oas_schema": (sub_to_oas_chema) => to_jsonschema(sub_to_oas_chema, subject),
                "example": (sub_example) => example(sub_example, subject),
            }));
        })(string = shape_7.string || (shape_7.string = {}));
    })(shape = lib_plankton.shape || (lib_plankton.shape = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:shape«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:shape« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:shape« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:shape«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var shape;
    (function (shape_8) {
        var email;
        (function (email) {
            /**
             */
            function make(options = {}) {
                options = Object.assign({
                    "soft": false,
                    "defaultvalue": undefined,
                    "description": undefined,
                }, options);
                return {
                    "core": {
                        "kind": "string",
                        "parameters": {
                            "soft": options.soft,
                            "defaultvalue": options.defaultvalue,
                            "description": options.description,
                            "pattern": "[^@]*@[^@]*",
                            "min_length": 0,
                            "max_length": 255,
                        }
                    },
                };
            }
            email.make = make;
            /**
             */
            function inspect(sub_inspect, subject, value) {
                return sub_inspect(subject.core, value);
            }
            /**
             */
            function show(sub_show, subject) {
                return sub_show(subject.core);
            }
            /**
             */
            function to_typescript_type(sub_to_typescript_type, subject) {
                return sub_to_typescript_type(subject.core);
            }
            /**
             */
            function to_jsonschema(sub_to_jsonschema, subject) {
                return sub_to_jsonschema(subject.core);
            }
            /**
             */
            function example(sub_example, subject) {
                return sub_example(subject.core);
            }
            shape_8.register("email", (parameters) => make({
                "soft": parameters.soft,
                "description": parameters.description,
                "defaultvalue": parameters.defaultvalue,
            }), (subject) => ({
                "inspect": (sub_inspect, value) => inspect(sub_inspect, subject, value),
                "show": (sub_show) => show(sub_show, subject),
                "to_typescript_type": (sub_to_typescript_type) => to_typescript_type(sub_to_typescript_type, subject),
                "to_jsonschema": (sub_to_jsonschema) => to_jsonschema(sub_to_jsonschema, subject),
                "to_oas_schema": (sub_to_oas_chema) => to_jsonschema(sub_to_oas_chema, subject),
                "example": (sub_example) => example(sub_example, subject),
            }));
        })(email = shape_8.email || (shape_8.email = {}));
    })(shape = lib_plankton.shape || (lib_plankton.shape = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:shape«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:shape« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:shape« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:shape«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var shape;
    (function (shape_9) {
        var list_;
        (function (list_) {
            /**
             */
            function make(shape_element, options = {}) {
                options = Object.assign({
                    "soft": false,
                    "defaultvalue": lib_plankton.pod.make_empty(),
                    "description": lib_plankton.pod.make_empty(),
                }, options);
                return {
                    "shape_element": shape_element,
                    "soft": options.soft,
                    "defaultvalue": ((options.defaultvalue === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.defaultvalue)),
                    "description": ((options.description === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.description)),
                };
            }
            list_.make = make;
            /**
             */
            function inspect(sub_inspect, subject, value) {
                let inspection = shape_9.inspection_create();
                if (value === null) {
                    if (subject.soft) {
                        // all good
                    }
                    else {
                        shape_9.inspection_add(inspection, "null is not allowed");
                    }
                }
                else {
                    const jstype_actual = typeof (value);
                    const jstype_expected = "object";
                    if (!(jstype_actual === jstype_expected)) {
                        lib_plankton.string.coin("expected JS-type '{{expected}}' but got '{{actual}}'", {
                            "expected": jstype_expected,
                            "actual": jstype_actual,
                        });
                    }
                    else {
                        if (!(value instanceof Array)) {
                            shape_9.inspection_add(inspection, "value does not seem to be an array-instance");
                        }
                        else {
                            value.forEach((element, index) => {
                                shape_9.inspection_extend(inspection, lib_plankton.string.coin("element #{{index}}", {
                                    "index": index.toFixed(0),
                                }), 
                                // subject.shape_element.inspect(element)
                                sub_inspect(subject.shape_element, element));
                            });
                        }
                    }
                }
                return inspection;
            }
            /**
             */
            function show(sub_show, subject) {
                const core = lib_plankton.string.coin("list<{{element}}>", {
                    "element": sub_show(subject.shape_element),
                });
                return (subject.soft ? ("~" + core) : core);
            }
            /**
             */
            function to_typescript_type(sub_to_typescript_type, subject) {
                const core = lib_plankton.string.coin("Array<{{element}}>", {
                    "element": sub_to_typescript_type(subject.shape_element),
                });
                return (subject.soft ? ("(null | " + core + ")") : core);
            }
            /**
             */
            function to_jsonschema(sub_to_jsonschema, subject) {
                const common = {
                    "description": lib_plankton.pod.distinguish(subject.description, () => undefined, x => x),
                    "default": lib_plankton.pod.distinguish(subject.defaultvalue, () => undefined, x => x),
                };
                const core = {
                    "type": "array",
                    "items": sub_to_jsonschema(subject.shape_element),
                };
                return ((subject.soft
                    ? {
                        "anyOf": [
                            Object.assign({ "type": "null" }, common),
                            Object.assign(core, common),
                        ]
                    }
                    : core));
            }
            /**
             */
            function example(sub_example, subject) {
                return (subject.soft
                    ? null
                    : [
                        sub_example(subject.shape_element)
                    ]);
            }
            shape_9.register("list", (parameters) => make(parameters.shape_element, {
                "soft": parameters.soft,
                "description": parameters.description,
                "defaultvalue": parameters.defaultvalue,
            }), (subject) => ({
                "inspect": (sub_inspect, value) => inspect(sub_inspect, subject, value),
                "show": (sub_show) => show(sub_show, subject),
                "to_typescript_type": (sub_to_typescript_type) => to_typescript_type(sub_to_typescript_type, subject),
                "to_jsonschema": (sub_to_jsonschema) => to_jsonschema(sub_to_jsonschema, subject),
                "to_oas_schema": (sub_to_oas_schema) => to_jsonschema(sub_to_oas_schema, subject),
                "example": (sub_example) => example(sub_example, subject),
            }));
        })(list_ = shape_9.list_ || (shape_9.list_ = {}));
    })(shape = lib_plankton.shape || (lib_plankton.shape = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:shape«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:shape« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:shape« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:shape«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var shape;
    (function (shape_10) {
        var map;
        (function (map) {
            /**
             */
            function make(shape_key, shape_value, options = {}) {
                options = Object.assign({
                    "soft": false,
                    "defaultvalue": lib_plankton.pod.make_empty(),
                    "description": lib_plankton.pod.make_empty(),
                }, options);
                return {
                    "shape_key": shape_key,
                    "shape_value": shape_value,
                    "soft": options.soft,
                    "defaultvalue": ((options.defaultvalue === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.defaultvalue)),
                    "description": ((options.description === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.description)),
                };
            }
            map.make = make;
            /**
             */
            function inspect(sub_inspect, subject, value) {
                let inspection = shape_10.inspection_create();
                if (value === null) {
                    if (subject.soft) {
                        // all good
                    }
                    else {
                        shape_10.inspection_add(inspection, "null is not allowed");
                    }
                }
                else {
                    const jstype_actual = typeof (value);
                    const jstype_expected = "object";
                    if (!(jstype_actual === jstype_expected)) {
                        lib_plankton.string.coin("expected JS-type '{{expected}}' but got '{{actual}}'", {
                            "expected": jstype_expected,
                            "actual": jstype_actual,
                        });
                    }
                    else {
                        Object.entries(value)
                            .forEach(([key, value]) => {
                            shape_10.inspection_extend(inspection, lib_plankton.string.coin("key '{{key}}'", {
                                "key": String(key),
                            }), sub_inspect(subject.shape_key, key));
                            shape_10.inspection_extend(inspection, lib_plankton.string.coin("value for '{{key}}'", {
                                "key": String(key),
                            }), sub_inspect(subject.shape_value, value));
                        });
                    }
                }
                return inspection;
            }
            /**
             */
            function show(sub_show, subject) {
                const core = lib_plankton.string.coin("map<{{key}},{{value}}>", {
                    "key": sub_show(subject.shape_key),
                    "value": sub_show(subject.shape_value),
                });
                return (subject.soft ? ("~" + core) : core);
            }
            /**
             */
            function to_typescript_type(sub_to_typescript_type, subject) {
                const core = lib_plankton.string.coin("Record<{{key}},{{value}}>", {
                    "key": sub_to_typescript_type(subject.shape_key),
                    "value": sub_to_typescript_type(subject.shape_key),
                });
                return (subject.soft ? ("(null | " + core + ")") : core);
            }
            /**
             */
            function to_jsonschema(sub_to_jsonschema, subject) {
                const common = {
                    "description": lib_plankton.pod.distinguish(subject.description, () => undefined, x => x),
                    "default": lib_plankton.pod.distinguish(subject.defaultvalue, () => undefined, x => x),
                };
                const core = {
                    "type": "object",
                    "additionalProperties": sub_to_jsonschema(subject.shape_value),
                    "properties": {},
                    "required": [],
                };
                return ((subject.soft
                    ? {
                        "anyOf": [
                            Object.assign({ "type": "null" }, common),
                            Object.assign(core, common),
                        ]
                    }
                    : core));
            }
            /**
             */
            function example(sub_example, subject) {
                return (subject.soft
                    ? null
                    : {});
            }
            shape_10.register("map", (parameters) => make(parameters.shape_key, parameters.shape_value, {
                "soft": parameters.soft,
                "description": parameters.description,
                "defaultvalue": parameters.defaultvalue,
            }), (subject) => ({
                "inspect": (sub_inspect, value) => inspect(sub_inspect, subject, value),
                "show": (sub_show) => show(sub_show, subject),
                "to_typescript_type": (sub_to_typescript_type) => to_typescript_type(sub_to_typescript_type, subject),
                "to_jsonschema": (sub_to_jsonschema) => to_jsonschema(sub_to_jsonschema, subject),
                "to_oas_schema": (sub_to_oas_schema) => to_jsonschema(sub_to_oas_schema, subject),
                "example": (sub_example) => example(sub_example, subject),
            }));
        })(map = shape_10.map || (shape_10.map = {}));
    })(shape = lib_plankton.shape || (lib_plankton.shape = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:shape«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:shape« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:shape« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:shape«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var shape;
    (function (shape_11) {
        var record;
        (function (record) {
            /**
             */
            function make(fields_raw, options = {}) {
                options = Object.assign({
                    "soft": false,
                    "defaultvalue": lib_plankton.pod.make_empty(),
                    "description": lib_plankton.pod.make_empty(),
                }, options);
                return {
                    "fields": fields_raw.map(field_raw => ({
                        "name": field_raw.name,
                        "shape": field_raw.shape,
                        "required": (field_raw.required ?? true)
                    })),
                    "soft": options.soft,
                    "defaultvalue": ((options.defaultvalue === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.defaultvalue)),
                    "description": ((options.description === undefined)
                        ? lib_plankton.pod.make_empty()
                        : lib_plankton.pod.make_filled(options.description)),
                };
            }
            record.make = make;
            /**
             */
            function inspect(sub_inspect, subject, value) {
                let inspection = shape_11.inspection_create();
                if (value === null) {
                    if (subject.soft) {
                        // all good
                    }
                    else {
                        shape_11.inspection_add(inspection, "null is not allowed");
                    }
                }
                else {
                    const jstype_actual = typeof (value);
                    const jstype_expected = "object";
                    if (!(jstype_actual === jstype_expected)) {
                        shape_11.inspection_add(inspection, lib_plankton.string.coin("expected JS-type '{{expected}}' but got '{{actual}}'", {
                            "expected": jstype_expected,
                            "actual": jstype_actual,
                        }));
                    }
                    else {
                        subject.fields.forEach(field => {
                            if (!(field.name in value)) {
                                if (field.required) {
                                    shape_11.inspection_add(inspection, "missing field '" + field.name + "'");
                                }
                                else {
                                    // do nothing
                                }
                            }
                            else {
                                const value_ = value[field.name];
                                shape_11.inspection_extend(inspection, ("field '" + field.name + "'"), sub_inspect(field.shape, value_));
                            }
                        });
                        // extra fields
                        {
                            const allowed = subject.fields.map(field => field.name);
                            (Object.keys(value)
                                .filter(name => (!allowed.includes(name)))
                                .forEach(name => {
                                shape_11.inspection_add(inspection, "extra field '" + name + "'");
                            }));
                        }
                    }
                }
                return inspection;
            }
            /**
             */
            function show(sub_show, subject) {
                const core = lib_plankton.string.coin("record<{{fields}}>", {
                    "fields": (subject.fields
                        .map(field => lib_plankton.string.coin("{{prefix}}{{name}}:{{shape}}", {
                        "prefix": (field.required ? "" : "?"),
                        "name": field.name,
                        "shape": sub_show(field.shape),
                    }))
                        .join(",")),
                });
                return (subject.soft ? ("~" + core) : core);
            }
            /**
             */
            function to_typescript_type(sub_to_typescript_type, subject) {
                const core = lib_plankton.string.coin("{{{fields}}}", {
                    "fields": (subject.fields
                        .map(field => lib_plankton.string.coin("{{name}}{{infix}}{{shape}}", {
                        "name": field.name,
                        "infix": (field.required ? ":" : "?:"),
                        "shape": sub_to_typescript_type(field.shape),
                    }))
                        .join(";")),
                });
                return (subject.soft ? ("(null | " + core + ")") : core);
            }
            /**
             */
            function to_jsonschema(sub_to_jsonschema, subject) {
                const common = {
                    "description": lib_plankton.pod.distinguish(subject.description, () => undefined, x => x),
                    "default": lib_plankton.pod.distinguish(subject.defaultvalue, () => undefined, x => x),
                };
                const core = {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": (Object.fromEntries(subject.fields
                        .map(field => ([
                        field.name,
                        sub_to_jsonschema(field.shape)
                    ])))),
                    "required": (subject.fields
                        .filter(field => field.required)
                        .map(field => field.name)),
                };
                return ((subject.soft
                    ? {
                        "anyOf": [
                            Object.assign({ "type": "null" }, common),
                            Object.assign(core, common),
                        ]
                    }
                    : core));
            }
            /**
             */
            function example(sub_example, subject) {
                return (subject.soft
                    ? null
                    : (Object.fromEntries(subject.fields
                        .filter(field => field.required)
                        .map(field => ([
                        field.name,
                        sub_example(field.shape)
                    ])))));
            }
            shape_11.register("record", (parameters) => make((parameters.fields
                .map(field_raw => ({
                "name": field_raw.name,
                "shape": field_raw.shape,
                "required": field_raw.required,
            }))), {
                "soft": parameters.soft,
                "description": parameters.description,
                "defaultvalue": parameters.defaultvalue,
            }), (subject) => ({
                "inspect": (sub_inspect, value) => inspect(sub_inspect, subject, value),
                "show": (sub_show) => show(sub_show, subject),
                "to_typescript_type": (sub_to_typescript_type) => to_typescript_type(sub_to_typescript_type, subject),
                "to_jsonschema": (sub_to_jsonschema) => to_jsonschema(sub_to_jsonschema, subject),
                "to_oas_schema": (sub_to_oas_schema) => to_jsonschema(sub_to_oas_schema, subject),
                "example": (sub_example) => example(sub_example, subject),
            }));
        })(record = shape_11.record || (shape_11.record = {}));
    })(shape = lib_plankton.shape || (lib_plankton.shape = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:code«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:code« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:code« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:code«. If not, see <http://www.gnu.org/licenses/>.
 */
/*
This file is part of »bacterio-plankton:code«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:code« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:code« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:code«. If not, see <http://www.gnu.org/licenses/>.
 */
/*
This file is part of »bacterio-plankton:code«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:code« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:code« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:code«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var code;
    (function (code) {
        /**
         * @author fenris
         */
        function inverse_encode(decode, to) {
            return decode(to);
        }
        code.inverse_encode = inverse_encode;
        /**
         * @author fenris
         */
        function inverse_decode(encode, from) {
            return encode(from);
        }
        code.inverse_decode = inverse_decode;
    })(code = lib_plankton.code || (lib_plankton.code = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:code«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:code« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:code« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:code«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var code;
    (function (code) {
        /**
         * @author fenris
         */
        var class_code_inverse = /** @class */ (function () {
            /**
             * @author fenris
             */
            function class_code_inverse(subject) {
                this.subject = subject;
            }
            /**
             * @implementation
             * @author fenris
             */
            class_code_inverse.prototype.encode = function (to) {
                var _this = this;
                return code.inverse_encode(function (x) { return _this.subject.decode(x); }, to);
            };
            /**
             * @implementation
             * @author fenris
             */
            class_code_inverse.prototype.decode = function (from) {
                var _this = this;
                return code.inverse_decode(function (x) { return _this.subject.encode(x); }, from);
            };
            return class_code_inverse;
        }());
        code.class_code_inverse = class_code_inverse;
    })(code = lib_plankton.code || (lib_plankton.code = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:code«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:code« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:code« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:code«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var code;
    (function (code) {
        /**
         * @author fenris
         */
        function pair_encode(encode_first, encode_second, from) {
            var between = encode_first(from);
            var to = encode_second(between);
            return to;
        }
        code.pair_encode = pair_encode;
        /**
         * @author fenris
         */
        function pair_decode(decode_first, decode_second, to) {
            var between = decode_second(to);
            var from = decode_first(between);
            return from;
        }
        code.pair_decode = pair_decode;
    })(code = lib_plankton.code || (lib_plankton.code = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:code«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:code« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:code« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:code«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var code;
    (function (code) {
        /**
         * @author fenris
         */
        var class_code_pair = /** @class */ (function () {
            /**
             * @author fenris
             */
            function class_code_pair(first, second) {
                this.first = first;
                this.second = second;
            }
            /**
             * @implementation
             * @author fenris
             */
            class_code_pair.prototype.encode = function (from) {
                var _this = this;
                return code.pair_encode(function (x) { return _this.first.encode(x); }, function (x) { return _this.second.encode(x); }, from);
            };
            /**
             * @implementation
             * @author fenris
             */
            class_code_pair.prototype.decode = function (to) {
                var _this = this;
                return code.pair_decode(function (x) { return _this.first.decode(x); }, function (x) { return _this.second.decode(x); }, to);
            };
            return class_code_pair;
        }());
        code.class_code_pair = class_code_pair;
    })(code = lib_plankton.code || (lib_plankton.code = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:code«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:code« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:code« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:code«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var code;
    (function (code) {
        /**
         * @author fenris
         */
        function chain_encode(encode_links, from) {
            var value = from;
            encode_links
                .forEach(function (link) {
                value = link(value);
            });
            return value;
        }
        code.chain_encode = chain_encode;
        /**
         * @author fenris
         */
        function chain_decode(decode_links, to) {
            var value = to;
            decode_links
                .reverse()
                .forEach(function (link) {
                value = link(value);
            });
            return value;
        }
        code.chain_decode = chain_decode;
    })(code = lib_plankton.code || (lib_plankton.code = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:code«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:code« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:code« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:code«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var code;
    (function (code) {
        /**
         * @author fenris
         */
        var class_code_chain = /** @class */ (function () {
            /**
             * @author fenris
             */
            function class_code_chain(links) {
                this.links = links;
            }
            /**
             * @implementation
             * @author fenris
             */
            class_code_chain.prototype.encode = function (from) {
                return code.chain_encode(this.links.map(function (link) { return (function (x) { return link.encode(x); }); }), from);
            };
            /**
             * @implementation
             * @author fenris
             */
            class_code_chain.prototype.decode = function (to) {
                return code.chain_decode(this.links.map(function (link) { return (function (x) { return link.decode(x); }); }), to);
            };
            return class_code_chain;
        }());
        code.class_code_chain = class_code_chain;
    })(code = lib_plankton.code || (lib_plankton.code = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:code«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:code« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:code« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:code«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var code;
    (function (code) {
        /**
         * @author Christian Fraß <frass@greenscale.de>
         */
        function flatten_encode(from, keys) {
            if (keys === void 0) { keys = null; }
            if (keys === null) {
                if (from.length > 0) {
                    keys = Object.keys(from[0]);
                }
                else {
                    throw (new Error("encoding impossible"));
                }
            }
            return {
                "keys": keys,
                "data": from.map(function (line) { return keys.map(function (name) { return line[name]; }); })
            };
        }
        code.flatten_encode = flatten_encode;
        /**
         * @author Christian Fraß <frass@greenscale.de>
         */
        function flatten_decode(to) {
            return (to.data
                .map(function (dataset) {
                var dataset_ = {};
                dataset
                    .forEach(function (value, index) {
                    var name = to.keys[index];
                    dataset_[name] = value;
                });
                return dataset_;
            }));
        }
        code.flatten_decode = flatten_decode;
    })(code = lib_plankton.code || (lib_plankton.code = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:code«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:code« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:code« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:code«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var code;
    (function (code) {
        /**
         * @author fenris
         */
        var class_code_flatten = /** @class */ (function () {
            /**
             * @author fenris
             */
            function class_code_flatten() {
            }
            /**
             * @implementation
             * @author fenris
             */
            class_code_flatten.prototype.encode = function (x) {
                return code.flatten_encode(x);
            };
            /**
             * @implementation
             * @author fenris
             */
            class_code_flatten.prototype.decode = function (x) {
                return code.flatten_decode(x);
            };
            return class_code_flatten;
        }());
        code.class_code_flatten = class_code_flatten;
    })(code = lib_plankton.code || (lib_plankton.code = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:url«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:url« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:url« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:url«. If not, see <http://www.gnu.org/licenses/>.
 */
/*
This file is part of »bacterio-plankton:url«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:url« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:url« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:url«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var url;
    (function (url_1) {
        /**
         * @author fenris
         */
        function encode(url) {
            let result = "";
            // protocol
            {
                if (url.hasOwnProperty("protocol") && (url.protocol !== null)) {
                    result += (url.protocol + ":");
                }
            }
            // host
            {
                if (url.hasOwnProperty("host") && (url.host !== null)) {
                    result += "//";
                    // username
                    {
                        if (url.hasOwnProperty("username") && (url.username !== null)) {
                            result += url.username;
                            // password
                            {
                                if (url.hasOwnProperty("password") && (url.password !== null)) {
                                    result += (":" + url.password);
                                }
                            }
                            result += "@";
                        }
                    }
                    result += url.host;
                }
            }
            // port
            {
                if (url.hasOwnProperty("port") && (url.port !== null)) {
                    result += (":" + url.port.toString());
                }
            }
            // path
            {
                if (url.hasOwnProperty("path") && (url.path !== null)) {
                    const path = encodeURI(url.path.join("/"));
                    result += ("/" + path);
                }
            }
            // arguments
            {
                if (url.hasOwnProperty("arguments") && (url.arguments !== null)) {
                    const search = (Object.entries(url.arguments)
                        .map(([key, value]) => (key + "=" + value))
                        .join("&"));
                    const search_ = encodeURI(search);
                    result += ("?" + search_);
                }
            }
            // hash
            {
                if (url.hasOwnProperty("hash") && (url.hash !== null)) {
                    result += ("#" + url.hash);
                }
            }
            return result;
        }
        url_1.encode = encode;
        /**
         * @author fenris
         * @todo arguments
         */
        function decode(url_raw) {
            const builtin_url = new URL(url_raw);
            return {
                "protocol": builtin_url.protocol.slice(0, -1),
                "host": builtin_url.hostname,
                "username": builtin_url.username,
                "password": builtin_url.password,
                "port": parseInt(builtin_url.port),
                "path": builtin_url.pathname.slice(1).split("/"),
                "hash": builtin_url.hash.slice(1),
                "arguments": (() => {
                    let arguments_ = {};
                    const search_parts = builtin_url.search.slice(1).split("&");
                    search_parts.forEach((search_part) => {
                        const components = search_part.split("=", 2);
                        const key = components[0];
                        const value = components[1];
                        arguments_[key] = value;
                    });
                    return arguments_;
                })(),
            };
        }
        url_1.decode = decode;
        /**
         * @author fenris
         */
        function implementation_code() {
            return {
                "encode": encode,
                "decode": decode,
            };
        }
        url_1.implementation_code = implementation_code;
    })(url = lib_plankton.url || (lib_plankton.url = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:url«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:url« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:url« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:url«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var url;
    (function (url) {
        /**
         * @author fenris
         */
        class class_url {
            /**
             * @author fenris
             */
            constructor() {
            }
            /**
             * @implementation
             * @author fenris
             */
            encode(x) {
                return url.encode(x);
            }
            /**
             * @implementation
             * @author fenris
             */
            decode(x) {
                return url.decode(x);
            }
        }
        url.class_url = class_url;
    })(url = lib_plankton.url || (lib_plankton.url = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:random«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:random« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:random« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:random«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var random;
    (function (random) {
        /**
         * @author fenris
         */
        function sequence(n) {
            return ((n <= 0) ? [] : sequence(n - 1).concat([n - 1]));
        }
        /**
         * @author fenris
         */
        function interpolate(x, y, t) {
            return (((1 - t) * x) + (t * y));
        }
        /**
         * @author fenris
         */
        var _statestack = [
            {
                "builtin": true,
                "seed": Date.now()
            },
        ];
        /**
         * @author fenris
         */
        function state_get() {
            return _statestack[_statestack.length - 1];
        }
        /**
         * @author fenris
         */
        function state_push(state) {
            _statestack.push(state);
        }
        random.state_push = state_push;
        /**
         * @author fenris
         */
        function state_pop() {
            if (_statestack.length <= 1) {
                throw (new Error("no state to pop"));
            }
            else {
                return _statestack.pop();
            }
        }
        random.state_pop = state_pop;
        /**
         * @author fenris
         */
        function seed_tick() {
            var state = state_get();
            state.seed = ((state.seed << 8) % 99767);
        }
        /**
         * @author fenris
         */
        function seed_get(tick) {
            if (tick === void 0) { tick = true; }
            if (tick) {
                seed_tick();
            }
            else {
                // do nothing
            }
            return state_get().seed;
        }
        /**
         * returns a random floating point number in the interval [0,1[
         *
         * @author fenris
         */
        function generate_unit() {
            if (state_get().builtin) {
                return Math.random();
            }
            else {
                return ((Math.sin(seed_get() << 8) + 1) / 2);
            }
        }
        random.generate_unit = generate_unit;
        /**
         * returns a random boolean value
         *
         * @param {float} [probability] the probability for the return-value "true"; default: 0.5
         * @author fenris
         */
        function generate_boolean(options) {
            if (options === void 0) { options = {}; }
            options = lib_plankton.base.object_merge({
                "probability": 0.5
            }, options);
            return (generate_unit() < options.probability);
        }
        random.generate_boolean = generate_boolean;
        /**
         * returns a random integer number in the interval [a,b]
         *
         * @param {int} [minimum] the left side of the halfopen interval (i.e. the smallest included value in the range)
         * @param {int} [minimum] the right side of the halfopen interval (i.e. the smallest excluded value in the range)
         * @author fenris
         */
        function generate_integer(options) {
            if (options === void 0) { options = {}; }
            options = lib_plankton.base.object_merge({
                "minimum": 0,
                "maximum": ((1 << 16) - 1)
            }, options);
            return Math.floor(interpolate(options.minimum, options.maximum + 1, generate_unit()));
        }
        random.generate_integer = generate_integer;
        random.generate_int = generate_integer;
        /**
         * returns a random floating point number in the given interval
         *
         * @author fenris
         */
        function generate_float(options) {
            if (options === void 0) { options = {}; }
            options = lib_plankton.base.object_merge({
                "minimum": 0.0,
                "maximum": 1.0
            }, options);
            return interpolate(options.minimum, options.maximum, generate_unit());
        }
        random.generate_float = generate_float;
        /**
         * returns a random date
         *
         * @author fenris
         */
        function generate_date(options) {
            if (options === void 0) { options = {}; }
            options = lib_plankton.base.object_merge({
                "minimum": new Date(0),
                "maximum": new Date(Date.now())
            }, options);
            return (new Date(generate_integer({
                "minimum": options.minimum.getTime(),
                "maximum": options.maximum.getTime()
            })));
        }
        random.generate_date = generate_date;
        /**
         * @author fenris
         */
        function generate_hexdigit() {
            return (this.generate_integer({ "minimum": 0, "maximum": 15 }).toString(16).toUpperCase());
        }
        random.generate_hexdigit = generate_hexdigit;
        /**
         * generates a random string with an optional prefix
         *
         * @author fenris
         */
        function generate_string(options) {
            if (options === void 0) { options = {}; }
            options = lib_plankton.base.object_merge({
                "length": 8
            }, options);
            return (sequence(options.length)
                .map(function (x) { return generate_integer({ "minimum": 65, "maximum": 90 }); })
                .map(function (x) { return String.fromCharCode(x); })
                .join("")
                .toLowerCase());
        }
        random.generate_string = generate_string;
        /**
         * chooses a value randomly from a list of values with weights (a higher weight means a higher probability to be chosen)
         *
         * @author fenris
         */
        function choose_weighted(sets) {
            var sum = sets.reduce(function (sum, set_) { return (sum + set_.weight); }, 0);
            if (sum === 0) {
                throw (new Error("weights sum up to zero; are all zero or are negative weights included?"));
            }
            else {
                var position_1 = generate_unit();
                return (sets.reduce(function (current, set_) {
                    var next = { "index": null, "value": null };
                    next.index = (current.index + (set_.weight / sum));
                    next.value = (((current.index <= position_1) && (position_1 < next.index))
                        ? set_.value
                        : current.value);
                    return next;
                }, { "index": 0, "value": null }).value);
            }
        }
        random.choose_weighted = choose_weighted;
        /**
         * chooses a value randomly from a list of values with equal probabilities
         *
         * @author fenris
         */
        function choose_uniformly(values) {
            return (choose_weighted(values.map(function (value) { return ({ "weight": 1, "value": value }); })));
        }
        random.choose_uniformly = choose_uniformly;
        /**
         * @author fenris
         */
        function shuffle(list) {
            var list_ = [];
            list.forEach(function (element) {
                var index = generate_integer({ "minimum": 0, "maximum": list_.length });
                list_.splice(index, 0, element);
            });
            return list_;
        }
        random.shuffle = shuffle;
        /**
         * @author fenris
         */
        function generate_vowel() {
            return (choose_weighted([
                { "weight": 1.0, "value": "u" },
                { "weight": 4.0, "value": "o" },
                { "weight": 6.0, "value": "a" },
                { "weight": 4.0, "value": "e" },
                { "weight": 1.0, "value": "i" },
            ]));
        }
        random.generate_vowel = generate_vowel;
        /**
         * @author fenris
         */
        function generate_halfvowel() {
            return (choose_weighted([
                { "weight": 4.0, "value": "y" },
                { "weight": 1.0, "value": "w" },
            ]));
        }
        random.generate_halfvowel = generate_halfvowel;
        /**
         * @author fenris
         */
        function generate_consonant() {
            return (choose_weighted([
                { "weight": 5.0, "value": "l" },
                { "weight": 5.0, "value": "m" },
                { "weight": 5.0, "value": "n" },
                { "weight": 4.0, "value": "b" },
                { "weight": 4.0, "value": "p" },
                { "weight": 4.0, "value": "d" },
                { "weight": 2.0, "value": "dj" },
                { "weight": 4.0, "value": "t" },
                { "weight": 2.0, "value": "tc" },
                { "weight": 4.0, "value": "g" },
                { "weight": 4.0, "value": "k" },
                { "weight": 3.0, "value": "v" },
                { "weight": 3.0, "value": "f" },
                { "weight": 3.0, "value": "z" },
                { "weight": 3.0, "value": "s" },
                { "weight": 3.0, "value": "j" },
                { "weight": 3.0, "value": "c" },
                { "weight": 2.0, "value": "r" },
                { "weight": 1.0, "value": "h" },
                { "weight": 1.0, "value": "x" },
            ]));
        }
        random.generate_consonant = generate_consonant;
        /**
         * @author fenris
         */
        function generate_letter() {
            return choose_uniformly([
                "a",
                "b",
                "c",
                "d",
                "e",
                "f",
                "g",
                "h",
                "i",
                "j",
                "k",
                "l",
                "m",
                "n",
                "o",
                "p",
                "q",
                "r",
                "s",
                "t",
                "u",
                "v",
                "w",
                "x",
                "y",
                "z",
            ]);
        }
        random.generate_letter = generate_letter;
        /**
         * @author fenris
         */
        function generate_syllable() {
            return (generate_consonant()
                +
                    generate_vowel()
                +
                    (generate_boolean({ "probability": 1 / 8 })
                        ? generate_halfvowel()
                        : "")
                +
                    (generate_boolean({ "probability": 1 / 4 })
                        ? generate_consonant()
                        : ""));
        }
        random.generate_syllable = generate_syllable;
        /**
         * @author fenris
         */
        function generate_word(options) {
            if (options === void 0) { options = {}; }
            options = lib_plankton.base.object_merge({
                "syllable_count_minimum": 2,
                "syllable_count_maximum": 5
            }, options);
            return (sequence(generate_integer({
                "minimum": options.syllable_count_minimum,
                "maximum": options.syllable_count_maximum
            }))
                .map(function (x) { return generate_syllable(); })
                .join(""));
        }
        random.generate_word = generate_word;
        /**
         * @author fenris
         */
        function generate_text(options) {
            if (options === void 0) { options = {}; }
            options = lib_plankton.base.object_merge({
                "word_count": generate_integer({ "minimum": 20, "maximum": 80 })
            }, options);
            return sequence(options.word_count).map(function (x) { return generate_word(); }).join(" ");
        }
        random.generate_text = generate_text;
        /**
         * @author fenris
         */
        function generate_city() {
            var str = (
            // prefix
            (generate_boolean({ "probability": 0.25 })
                ? choose_uniformly([
                    "unter",
                    "ober",
                    "mittel",
                    "groß",
                    "klein",
                    "neu",
                    "alt",
                ])
                : "")
                +
                    // infix
                    choose_uniformly([
                        "stein",
                        "frei",
                        "berns",
                        "kirch",
                        "fels",
                        "weiden",
                        "buchen",
                        "eichen",
                        "eiben",
                        "linden",
                        "ulmen",
                        "birken",
                        "eschen",
                        "erlen",
                        "grün",
                        "kreuz",
                        "wald",
                        "reichen",
                        "lieben",
                        "schön",
                        "heinrichs",
                        "friedrichs",
                        "johann",
                        "walters",
                        "günthers",
                        "rupperts",
                        "wilhems",
                        "albert",
                    ])
                +
                    // suffix
                    choose_uniformly([
                        "feld",
                        "thal",
                        "berg",
                        "burg",
                        "stadt",
                        "dorf",
                        "heim",
                        "bach",
                        "au",
                        "rode",
                        "ing",
                        "nitz",
                        "hausen",
                    ]));
            return (str[0].toUpperCase() + str.substring(1));
        }
        random.generate_city = generate_city;
        /**
         * @author fenris
         */
        function generate_street() {
            var str = (
            // prefix
            choose_uniformly([
                "haupt",
                "neben",
                "bahnhof",
                "markt",
                "augustus",
                "wilhelm",
                "albert",
                "friedrich",
                "maximilian",
                "wagner",
                "linden",
                "eichen",
                "buchen",
                "tannen",
                "pappel",
                "ulmen",
                "eschen",
            ])
                +
                    // core
                    choose_uniformly([
                        "straße",
                        "weg",
                        "allee",
                        "pfad",
                        "hain",
                        "anger",
                        "passage",
                        "platz",
                    ])
                +
                    // number
                    (" " + generate_integer({ "minimum": 1, "maximum": 80 }).toString()));
            return (str[0].toUpperCase() + str.substring(1));
        }
        random.generate_street = generate_street;
        /**
         * @author fenris
         */
        function generate_guid(options) {
            if (options === void 0) { options = {}; }
            options = lib_plankton.base.object_merge({
                "with_braces": false
            }, options);
            /*
            return (
                [8,4,4,4,12]
                .map(length => sequence(length).map(_ => this.generate_hexdigit()).join(""))
                .join("-")
            );
             */
            var guid = ("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(new RegExp("[xy]", "g"), function (symbol) {
                var r = generate_integer({ "minimum": 0, "maximum": 15 });
                var v = ((symbol == "y") ? ((r & 0x3) | 0x8) : r);
                return (v.toString(16).toUpperCase());
            }));
            return (options.with_braces
                ? ("{" + guid + "}")
                : guid);
        }
        random.generate_guid = generate_guid;
        /**
         * @author fenris
         */
        function generate_domain(options) {
            if (options === void 0) { options = {}; }
            options = lib_plankton.base.object_merge({
                "steps": 3
            }, options);
            return (sequence(generate_integer({ "minimum": 1, "maximum": options.steps }))
                .map(function () { return generate_word(); })
                // tld
                .concat(sequence(generate_integer({ "minimum": 2, "maximum": 3 }))
                .map(function () { return generate_letter(); })
                .join(""))).join(".");
        }
        /**
         * @author fenris
         */
        function generate_url() {
            return (lib_plankton.url.encode({
                "protocol": choose_uniformly([
                    "http",
                    "https",
                    "git",
                    "smb",
                    "ftp",
                ]),
                "host": generate_domain(),
                "port": generate_integer({ "minimum": 20, "maximum": 99999 }),
                "path": (sequence(generate_integer({ "minimum": 0, "maximum": 3 }))
                    .map(function () { return generate_word(); })),
                "arguments": choose_uniformly([
                    null,
                    Object.fromEntries(sequence(generate_integer({ "minimum": 0, "maximum": 3 }))
                        .map(function () { return ([
                        generate_word(),
                        generate_integer().toFixed(0),
                    ]); })),
                ])
            }));
        }
        random.generate_url = generate_url;
        /**
         * @author fenris
         */
        function generate_email_address() {
            return (
            // user
            generate_word()
                +
                    "@"
                +
                    generate_domain({ "steps": 1 }));
        }
        random.generate_email_address = generate_email_address;
        /**
         * @author fenris
         */
        function generate_telephone_number() {
            return (
            // country prefix
            ("+"
                +
                    generate_integer({ "minimum": 1, "maximum": 999 }).toFixed(0))
                +
                    " "
                +
                    // provider
                    +(sequence(3)
                        .map(function () { return generate_integer({ "minimum": 0, "maximum": 9 }); })
                        .join(""))
                +
                    " "
                +
                    // custom
                    +(sequence(7)
                        .map(function () { return generate_integer({ "minimum": 0, "maximum": 9 }); })
                        .join("")));
        }
        random.generate_telephone_number = generate_telephone_number;
        /**
         * @author fenris
         */
        function generate_time() {
            return {
                "hour": generate_integer({ "minimum": 0, "maximum": 23 }),
                "minute": generate_integer({ "minimum": 0, "maximum": 59 }),
                "second": generate_integer({ "minimum": 0, "maximum": 59 })
            };
        }
        random.generate_time = generate_time;
        /**
         * @author fenris
         * @deprecated
         * @todo remove
         */
        function generate_for_shape(shape) {
            throw (new Error("deprecated! use lib_shape!"));
        }
        random.generate_for_shape = generate_for_shape;
        /**
         * @author fenris
         */
        /*
        export function generate_for_shape_(
            shape : lib_plankton.shape.type_shape
        ) : any
        {
            switch (shape.name) {
                case "boolean": {
                    return generate_boolean();
                    break;
                }
                case "int": {
                    const min = shape.parameters["min"];
                    const max = shape.parameters["max"];
                    return generate_integer(
                        {
                            "minimum": ((min == null) ? undefined : min),
                            "maximum": ((max == null) ? undefined : max),
                        }
                    );
                    break;
                }
                case "float": {
                    return generate_float(
                        {
                            "minimum": shape.parameters["min"],
                            "maximum": shape.parameters["max"],
                        }
                    );
                    break;
                }
                case "string": {
                    return generate_string();
                    break;
                }
                case "url": {
                    return generate_url();
                    break;
                }
                case "email": {
                    return generate_email_address();
                    break;
                }
                case "time": {
                    return generate_time();
                    break;
                }
                case "array": {
                    return (
                        sequence(generate_integer({"minimum": 2, "maximum": 5}))
                        .map(() => generate_for_shape_(shape.parameters["shape_element"]))
                    );
                    break;
                }
                case "object": {
                    return Object.fromEntries(
                        shape.parameters["fields"]
                        .map(
                            field => ([
                                field["name"],
                                generate_for_shape_(field["shape"]),
                            ])
                        )
                    );
                    break;
                }
                case "date": {
                    return generate_date();
                    break;
                }
                case "enumeration": {
                    return choose_uniformly<any>(shape.parameters["options"])["value"];
                    break;
                }
                default: {
                    const message : string = `unhandled shape kind '${shape.name}'`;
                    // console.warn(message);
                    // return null;
                    throw (new Error(message));
                    break;
                }
            }
        }
         */
    })(random = lib_plankton.random || (lib_plankton.random = {}));
})(lib_plankton || (lib_plankton = {}));
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (g && (g = 0, op[0] && (_ = 0)), _) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
/*
This file is part of »bacterio-plankton:storage«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:session« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:session« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:storage«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var session;
    (function (session_1) {
        /**
         */
        var _conf = null;
        /**
         */
        function check_conf() {
            if (_conf === null) {
                throw (new Error("session system not set up yet"));
            }
            else {
                // do nothing
            }
        }
        /**
         */
        function begin(name, options) {
            if (options === void 0) { options = {}; }
            return __awaiter(this, void 0, void 0, function () {
                var key, attempts, session_old, error_1, session_2, session_raw;
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            options = Object.assign({
                                "lifetime": _conf.default_lifetime,
                                "data": null
                            }, options);
                            check_conf();
                            key = null;
                            attempts = 0;
                            _a.label = 1;
                        case 1:
                            if (!true) return [3 /*break*/, 6];
                            attempts += 1;
                            key = lib_plankton.call.convey(_conf.key_length, [
                                function (x) { return (new Array(x)).fill(null); },
                                function (x) { return x.map(function () { return lib_plankton.random.generate_hexdigit(); }); },
                                function (x) { return x.join(""); },
                            ]);
                            session_old = null;
                            _a.label = 2;
                        case 2:
                            _a.trys.push([2, 4, , 5]);
                            return [4 /*yield*/, _conf.data_chest.read(key)];
                        case 3:
                            session_old = _a.sent();
                            return [3 /*break*/, 5];
                        case 4:
                            error_1 = _a.sent();
                            session_old = null;
                            return [3 /*break*/, 5];
                        case 5:
                            if (session_old !== null) {
                                key = null;
                                if (attempts >= _conf.key_max_attempts) {
                                    // fail
                                    return [3 /*break*/, 6];
                                }
                                else {
                                    // retry
                                }
                            }
                            else {
                                // suuccess
                                return [3 /*break*/, 6];
                            }
                            return [3 /*break*/, 1];
                        case 6:
                            if (!(key === null)) return [3 /*break*/, 7];
                            throw (new Error("failed to generate unique session key"));
                        case 7:
                            session_2 = {
                                "key": key,
                                "name": name,
                                "expiry": (lib_plankton.base.get_current_timestamp() + options.lifetime),
                                "data": options.data
                            };
                            session_raw = {
                                "key": session_2.key,
                                "name": session_2.name,
                                "expiry": Math.floor(session_2.expiry),
                                "data": JSON.stringify(session_2.data)
                            };
                            lib_plankton.call.timeout(function () {
                                lib_plankton.log.info("session_dropping_due_to_being_expired", {
                                    "key": key,
                                    "name": name,
                                    "lifetime": options.lifetime
                                });
                                end(key);
                            }, options.lifetime);
                            return [4 /*yield*/, _conf.data_chest.write(key, session_raw)];
                        case 8:
                            _a.sent();
                            return [2 /*return*/, Promise.resolve(key)];
                    }
                });
            });
        }
        session_1.begin = begin;
        /**
         */
        function get(key) {
            check_conf();
            return (_conf.data_chest.read(key)
                .then(function (session_raw) {
                var session = {
                    "key": session_raw["key"],
                    "name": session_raw["name"],
                    "expiry": session_raw["expiry"],
                    "data": JSON.parse(session_raw["data"])
                };
                var now = lib_plankton.base.get_current_timestamp();
                if (now > session.expiry) {
                    lib_plankton.log.info("session_dropping_due_to_being_stale", {
                        "key": session.key,
                        "name": session.name
                    });
                    end(key);
                    return Promise.reject();
                }
                else {
                    return Promise.resolve(session);
                }
            }));
        }
        session_1.get = get;
        /**
         */
        function end(key) {
            check_conf();
            return _conf.data_chest["delete"](key);
        }
        session_1.end = end;
        /**
         */
        function setup(options) {
            if (options === void 0) { options = {}; }
            return __awaiter(this, void 0, void 0, function () {
                return __generator(this, function (_a) {
                    switch (_a.label) {
                        case 0:
                            options = Object.assign({
                                "key_length": 16,
                                "key_max_attempts": 3,
                                "default_lifetime": 900,
                                "data_chest": lib_plankton.storage.memory.implementation_chest({}),
                                "clear": false
                            }, options);
                            _conf = {
                                "key_length": options.key_length,
                                "key_max_attempts": options.key_max_attempts,
                                "default_lifetime": options.default_lifetime,
                                "data_chest": options.data_chest
                            };
                            if (!options.clear) return [3 /*break*/, 2];
                            return [4 /*yield*/, _conf.data_chest.clear()];
                        case 1:
                            _a.sent();
                            return [3 /*break*/, 2];
                        case 2: return [2 /*return*/, Promise.resolve(undefined)];
                    }
                });
            });
        }
        session_1.setup = setup;
    })(session = lib_plankton.session || (lib_plankton.session = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:json«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:json« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:json« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:json«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var json;
    (function (json) {
        /**
         * @author fenris
         */
        function encode(x, formatted = false) {
            return JSON.stringify(x, undefined, formatted ? "\t" : undefined);
        }
        json.encode = encode;
        /**
         * @author fenris
         */
        function decode(x) {
            return JSON.parse(x);
        }
        json.decode = decode;
    })(json = lib_plankton.json || (lib_plankton.json = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:json«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:json« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:json« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:json«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var json;
    (function (json) {
        /**
         * @author fenris
         */
        class class_json {
            /**
             * @author fenris
             */
            constructor() {
            }
            /**
             * @implementation
             * @author fenris
             */
            encode(x) {
                return json.encode(x);
            }
            /**
             * @implementation
             * @author fenris
             */
            decode(x) {
                return json.decode(x);
            }
        }
        json.class_json = class_json;
    })(json = lib_plankton.json || (lib_plankton.json = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:object«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:object« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:object« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:object«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var object;
    (function (object_1) {
        /**
         * @author fenris
         */
        function fetch(object, fieldname, fallback, escalation) {
            if (fallback === void 0) { fallback = null; }
            if (escalation === void 0) { escalation = 1; }
            if ((fieldname in object) && (object[fieldname] !== undefined)) {
                return object[fieldname];
            }
            else {
                switch (escalation) {
                    case 0: {
                        return fallback;
                        break;
                    }
                    case 1: {
                        var message = ("field '".concat(fieldname, "' not in structure"));
                        message += ("; using fallback value '".concat(String(fallback), "'"));
                        // console.warn(message);
                        return fallback;
                        break;
                    }
                    case 2: {
                        var message = ("field '".concat(fieldname, "' not in structure"));
                        throw (new Error(message));
                        break;
                    }
                    default: {
                        throw (new Error("invalid escalation level ".concat(escalation)));
                        break;
                    }
                }
            }
        }
        object_1.fetch = fetch;
        /**
         * @author fenris
         */
        function map(object_from, transformator) {
            var object_to = {};
            Object.keys(object_from).forEach(function (key) { return (object_to[key] = transformator(object_from[key], key)); });
            return object_to;
        }
        object_1.map = map;
        /**
         * @desc gibt ein Objekt mit bestimmten Einträgen des Eingabe-Objekts zurück
         * @author fenris
         */
        function filter(object_from, predicate) {
            var object_to = {};
            Object.keys(object_from).forEach(function (key) {
                var value = object_from[key];
                if (predicate(value, key)) {
                    object_to[key] = value;
                }
            });
            return object_to;
        }
        object_1.filter = filter;
        /**
         * @desc wandelt ein Array mit Einträgen der Form {key,value} in ein entsprechendes Objekt um
         * @author fenris
         */
        function from_array(array) {
            var object = {};
            array.forEach(function (entry) { return (object[entry.key] = entry.value); });
            return object;
        }
        object_1.from_array = from_array;
        /**
         * @desc wandelt ein Objekt in ein entsprechendes Array mit Einträgen der Form {key,value} um
         * @author fenris
         */
        function to_array(object) {
            var array = [];
            Object.keys(object).forEach(function (key) { return array.push({ "key": key, "value": object[key] }); });
            return array;
        }
        object_1.to_array = to_array;
        /**
         * @desc gibt eine Liste von Schlüsseln eines Objekts zurück
         * @author fenris
         */
        function keys(object) {
            return Object.keys(object);
        }
        object_1.keys = keys;
        /**
         * @desc gibt eine Liste von Werten eines Objekts zurück
         * @author fenris
         */
        function values(object) {
            return to_array(object).map(function (entry) { return entry.value; });
        }
        object_1.values = values;
        /**
         * @desc liest ein Baum-artiges Objekt an einer bestimmten Stelle aus
         * @author fenris
         */
        function path_read(object, path, fallback, escalation) {
            if (fallback === void 0) { fallback = null; }
            if (escalation === void 0) { escalation = 1; }
            var steps = ((path.length == 0) ? [] : path.split("."));
            if (steps.length == 0) {
                throw (new Error("empty path"));
            }
            else {
                var position_1 = object;
                var reachable = (position_1 != null) && steps.slice(0, steps.length - 1).every(function (step) {
                    position_1 = lib_plankton.object.fetch(position_1, step, null, 0);
                    return (position_1 != null);
                });
                if (reachable) {
                    return lib_plankton.object.fetch(position_1, steps[steps.length - 1], fallback, escalation);
                }
                else {
                    return lib_plankton.object.fetch({}, "_dummy_", fallback, escalation);
                }
            }
        }
        object_1.path_read = path_read;
        /**
         * @desc schreibt einen Wert an eine bestimmte Stelle in einem Baum-artigen Objekt
         * @author fenris
         */
        function path_write(object, path, value, construct) {
            if (construct === void 0) { construct = true; }
            var steps = ((path.length == 0) ? [] : path.split("."));
            if (steps.length == 0) {
                throw (new Error("empty path"));
            }
            else {
                var position_2 = object;
                var reachable = steps.slice(0, steps.length - 1).every(function (step) {
                    var position_ = lib_plankton.object.fetch(position_2, step, null, 0);
                    if (position_ == null) {
                        if (construct) {
                            position_2[step] = {};
                            position_2 = position_2[step];
                            return true;
                        }
                        else {
                            return false;
                        }
                    }
                    else {
                        position_2 = position_;
                        return true;
                    }
                });
                if (reachable) {
                    position_2[steps[steps.length - 1]] = value;
                }
                else {
                    var message = ("path '".concat(path, "' does not exist and may not be constructed"));
                    throw (new Error(message));
                }
            }
        }
        object_1.path_write = path_write;
        /**
         * @desc prüft ob ein Objekt einem bestimmten Muster entspricht
         * @param {Object} object das zu prüfende Objekt
         * @param {Object} pattern das einzuhaltende Muster
         * @param {Function} connlate eine Funktion zum Feststellen der Gleichheit von Einzelwerten
         * @author fenris
         */
        function matches(object, pattern, collate) {
            if (collate === void 0) { collate = instance_collate; }
            return Object.keys(pattern).every(function (key) { return collate(pattern[key], object[key]); });
        }
        object_1.matches = matches;
        /**
         * @desc erzeugt eine Projektion eines Baum-artigen Objekts in ein Listen-artiges Objekt
         * @param {string} [separator] welches Zeichen als Trenner zwischen zwei Pfad-Schritten verwendet werden soll
         * @author fenris
         */
        function flatten(value, separator, key_for_element) {
            if (separator === void 0) { separator = "."; }
            if (key_for_element === void 0) { key_for_element = (function (index) { return ("element_" + index.toFixed(0)); }); }
            var integrate = function (result, key_, value_) {
                if (value_ == null) {
                    result[key_] = value_;
                }
                else {
                    // primitive Werte direkt übernehmen
                    if (typeof (value_) != "object") {
                        result[key_] = value_;
                    }
                    // sonst durch rekursiven Aufruf die flache Variante des Wertes ermitteln und einarbeiten
                    else {
                        var result_1 = flatten(value_);
                        Object.keys(result_1)
                            .forEach(function (key__) {
                            var value__ = result_1[key__];
                            var key_new = (key_ + separator + key__);
                            result[key_new] = value__;
                        });
                    }
                }
            };
            if ((value === null) || (value === undefined)) {
                return null;
            }
            else {
                var result_2 = {};
                if (typeof (value) != "object") {
                    result_2["value"] = value;
                }
                else {
                    if (value instanceof Array) {
                        var array = (value);
                        array
                            .forEach(function (element, index) {
                            integrate(result_2, key_for_element(index), element);
                        });
                    }
                    else {
                        var object_2 = (value);
                        Object.keys(object_2)
                            .forEach(function (key) {
                            integrate(result_2, key, object_2[key]);
                        });
                    }
                }
                return result_2;
            }
        }
        object_1.flatten = flatten;
        /**
         * @author fenris
         */
        function clash(x, y, _a) {
            var _b = _a === void 0 ? {} : _a, _c = _b["overwrite"], overwrite = _c === void 0 ? true : _c, _d = _b["hooks"], _e = _d === void 0 ? {} : _d, _f = _e["existing"], hook_existing = _f === void 0 ? null : _f;
            if (hook_existing == null) {
                (function (key, value_old, value_new) { return console.warn("field ".concat(key, " already defined")); });
            }
            var z = {};
            Object.keys(x).forEach(function (key) {
                z[key] = x[key];
            });
            Object.keys(y).forEach(function (key) {
                if (key in z) {
                    if (hook_existing != null) {
                        hook_existing(key, z[key], y[key]);
                    }
                    if (overwrite) {
                        z[key] = y[key];
                    }
                }
                else {
                    z[key] = y[key];
                }
            });
            return z;
        }
        object_1.clash = clash;
        /**
         * @author fenris
         */
        function patch(core, mantle, deep, path) {
            if (deep === void 0) { deep = true; }
            if (path === void 0) { path = null; }
            if (mantle == null) {
                console.warn("mantle is null; core was", core);
            }
            else {
                Object.keys(mantle).forEach(function (key) {
                    var path_ = ((path == null) ? key : "".concat(path, ".").concat(key));
                    var value_mantle = mantle[key];
                    if (!(key in core)) {
                        if ((typeof (value_mantle) == "object") && (value_mantle != null) && deep) {
                            if (value_mantle instanceof Array) {
                                core[key] = [];
                                value_mantle.forEach(function (element) {
                                    if ((typeof (element) == "object") && (element != null)) {
                                        var element_ = {};
                                        patch(element_, element);
                                        core[key].push(element_);
                                    }
                                    else {
                                        core[key].push(element);
                                    }
                                });
                            }
                            else {
                                core[key] = {};
                                patch(core[key], value_mantle, deep, path_);
                            }
                        }
                        else {
                            core[key] = value_mantle;
                        }
                    }
                    else {
                        var value_core = core[key];
                        if (typeof (value_core) == typeof (value_mantle)) {
                            if ((typeof (value_mantle) == "object") && (value_mantle != null) && deep) {
                                patch(core[key], value_mantle, deep, path_);
                            }
                            else {
                                core[key] = value_mantle;
                            }
                        }
                        else {
                            if ((value_core != null) && (value_mantle != null)) {
                                var message = "objects have different shapes at path '".concat(path_, "'; core has type '").concat(typeof (value_core), "' and mantle has type '").concat(typeof (value_mantle), "'");
                                console.warn(message);
                            }
                            core[key] = value_mantle;
                            // throw (new Error(message));
                        }
                    }
                });
            }
        }
        object_1.patch = patch;
        /**
         * @author fenris
         */
        function patched(core, mantle, deep) {
            if (deep === void 0) { deep = undefined; }
            var result = {};
            patch(result, core, deep);
            patch(result, mantle, deep);
            return result;
        }
        object_1.patched = patched;
        /**
         * @author fenris
         */
        function attached(object, key, value) {
            var mantle = {};
            mantle[key] = value;
            return patched(object, mantle, false);
        }
        object_1.attached = attached;
        /**
         * @author fenris
         */
        function copy(object) {
            return patched({}, object);
        }
        object_1.copy = copy;
    })(object = lib_plankton.object || (lib_plankton.object = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:markdown«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:markdown« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:markdown« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:markdown«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var markdown;
    (function (markdown) {
        /**
         * @author fenris
         */
        function code(content) {
            return lib_plankton.string.coin("`{{content}}`", {
                "content": content
            });
        }
        markdown.code = code;
        /**
         * @author fenris
         */
        function paragraph(content) {
            return lib_plankton.string.coin("{{content}}\n\n", {
                "content": content
            });
        }
        markdown.paragraph = paragraph;
        /**
         * @author fenris
         */
        function sectionhead(level, content) {
            return lib_plankton.string.coin("{{grids}} {{content}}\n\n", {
                "grids": lib_plankton.string.repeat("#", level),
                "content": content
            });
        }
        markdown.sectionhead = sectionhead;
    })(markdown = lib_plankton.markdown || (lib_plankton.markdown = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:api«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:api« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:api« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:api«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var api;
    (function (api) {
        /**
         */
        let enum_checklevel;
        (function (enum_checklevel) {
            enum_checklevel["none"] = "none";
            enum_checklevel["soft"] = "soft";
            enum_checklevel["hard"] = "hard";
        })(enum_checklevel = api.enum_checklevel || (api.enum_checklevel = {}));
        /**
         */
        class class_error_permission_denied extends Error {
        }
        api.class_error_permission_denied = class_error_permission_denied;
    })(api = lib_plankton.api || (lib_plankton.api = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:api«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:api« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:api« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:api«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var api;
    (function (api_1) {
        /**
         * @throws Error if the inspection had foundings and the level is high enough
         * @author fenris
         */
        function validate(level, shape, value, options = {}) {
            options = lib_plankton.object.patched({
                "kind": "value",
                "message_factory": ((kind, findings) => ("malformed " + kind + ": " + findings.join("; "))),
            }, options);
            if (level === api_1.enum_checklevel.none) {
                return value;
            }
            else {
                const inspection = lib_plankton.shape.inspect_flat(shape, value);
                if (inspection.length === 0) {
                    return value;
                }
                else {
                    const message = options.message_factory(options.kind, inspection);
                    switch (level) {
                        case api_1.enum_checklevel.soft: {
                            console.warn(message);
                            return value;
                            break;
                        }
                        case api_1.enum_checklevel.hard:
                        default:
                            {
                                throw (new Error(message));
                                break;
                            }
                    }
                }
            }
        }
        /**
         * @author fenris
         */
        function make(title) {
            const api = {
                "title": title,
                "actions": {},
            };
            return api;
        }
        api_1.make = make;
        /**
         * @throws Error if a action with the given name has already been registered
         * @author fenris
         */
        function register(api, name, options = {}) {
            options = /*lib_plankton.object.patched*/ Object.assign({
                "active": (version) => true,
                "execution": (version, environment, input) => lib_plankton.call.promise_reject("not implemented"),
                "restriction": (version, environment) => true,
                "input_shape": (version) => ({ "kind": "any" }),
                "output_shape": (version) => ({ "kind": "any" }),
                "title": null,
                "description": null,
            }, options);
            if (api.actions.hasOwnProperty(name)) {
                throw (new Error("an action with the name '" + name + "' has already been registered"));
            }
            else {
                const action = {
                    "name": name,
                    "active": options.active,
                    "execution": options.execution,
                    "restriction": options.restriction,
                    "input_shape": options.input_shape,
                    "output_shape": options.output_shape,
                    "title": options.title,
                    "description": options.description,
                };
                api.actions[name] = action;
            }
        }
        api_1.register = register;
        /**
         * @throws Error if not found
         * @author fenris
         */
        function get_action(api, name) {
            if (api.actions.hasOwnProperty(name)) {
                const action = api.actions[name];
                return action;
            }
            else {
                throw (new Error("no action with name '" + name + "'"));
            }
        }
        api_1.get_action = get_action;
        /**
         * @author fenris
         */
        function call(api, name, options = {}) {
            options = /*lib_plankton.object.patched*/ Object.assign({
                "version": null,
                "input": null,
                "environment": {},
                "checklevel_restriction": api_1.enum_checklevel.hard,
                "checklevel_input": api_1.enum_checklevel.soft,
                "checklevel_output": api_1.enum_checklevel.soft,
            }, options);
            return (lib_plankton.call.promise_resolve(undefined)
                // get action
                .then(() => lib_plankton.call.promise_resolve(get_action(api, name)))
                .then((action) => (lib_plankton.call.promise_resolve(undefined)
                // check permission
                .then(() => {
                let conf;
                switch (options.checklevel_restriction) {
                    case api_1.enum_checklevel.none: {
                        conf = {
                            "actual_check": false,
                            "escalate": false,
                        };
                        break;
                    }
                    case api_1.enum_checklevel.soft: {
                        conf = {
                            "actual_check": true,
                            "escalate": false,
                        };
                        break;
                    }
                    default:
                    case api_1.enum_checklevel.hard: {
                        conf = {
                            "actual_check": true,
                            "escalate": true,
                        };
                        break;
                    }
                }
                return ((conf.actual_check
                    ? action.restriction(options.version, options.environment)
                    : Promise.resolve(true))
                    .then((valid) => {
                    if (!valid) {
                        if (conf.escalate) {
                            return Promise.reject(new api_1.class_error_permission_denied());
                        }
                        else {
                            lib_plankton.log.warning("api_permission_missing", {
                                "version": options.version,
                                "environment": options.environment,
                                "action_name": action.name,
                            });
                            return Promise.resolve(null);
                        }
                    }
                    else {
                        return Promise.resolve(null);
                    }
                }));
            })
                // validate and adjust input
                .then(() => lib_plankton.call.promise_resolve(validate(options.checklevel_input, action.input_shape(options.version), options.input, {
                "kind": "input",
            })))
                // execute
                .then((input) => action.execution(options.version, options.environment, options.input))
                // validate output
                .then((output) => lib_plankton.call.promise_resolve(validate(options.checklevel_output, action.output_shape(options.version), output, {
                "kind": "output",
            }))))));
        }
        api_1.call = call;
        /**
         * @author fenris
         */
        function generate_documentation_for_action(api, name, options = {}) {
            options = Object.assign({
                "version": null,
            }, options);
            const action = get_action(api, name);
            let result = "";
            if (!action.active(options.version)) {
                // do nothing
            }
            else {
                // name
                {
                    result += lib_plankton.markdown.sectionhead(2, lib_plankton.markdown.code(action.name));
                }
                // description
                {
                    result += lib_plankton.markdown.sectionhead(3, "Description");
                    result += lib_plankton.markdown.paragraph(action.description ?? "-");
                }
                // input shape
                {
                    result += lib_plankton.markdown.sectionhead(3, "Input");
                    result += lib_plankton.markdown.paragraph(lib_plankton.markdown.code(lib_plankton.shape.show(action.input_shape(options.version))));
                }
                // output shape
                {
                    result += lib_plankton.markdown.sectionhead(3, "Output");
                    result += lib_plankton.markdown.paragraph(lib_plankton.markdown.code(lib_plankton.shape.show(action.output_shape(options.version))));
                }
            }
            return result;
        }
        api_1.generate_documentation_for_action = generate_documentation_for_action;
        /**
         * @author fenris
         */
        function generate_documentation(api, options = {}) {
            options = Object.assign({
                "version": null,
            }, options);
            let result = "";
            result += lib_plankton.markdown.paragraph(api.title);
            result += lib_plankton.markdown.sectionhead(1, "Actions");
            // iterate through actions and use "generate_documentation_for_action"
            Object.entries(api.actions)
                .forEach(([action_name, action]) => {
                result += generate_documentation_for_action(api, action_name, {
                    "version": options.version,
                });
            });
            return result;
        }
        api_1.generate_documentation = generate_documentation;
    })(api = lib_plankton.api || (lib_plankton.api = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:api«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:api« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:api« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:api«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var api;
    (function (api) {
        /**
         * @author fenris
         */
        class class_api {
            /**
             * @author fenris
             */
            constructor(subject) {
                this.subject = subject;
            }
            /**
             * @author fenris
             */
            static create(name) {
                const subject = api.make(name);
                return (new class_api(subject));
            }
            /**
             * @author fenris
             */
            register(name, options = {}) {
                return api.register(this.subject, name, options);
            }
            /**
             * @author fenris
             */
            call(name, options = {}) {
                return api.call(this.subject, name, options);
            }
            /**
             * @author fenris
             */
            generate_documentation_for_action(name) {
                return api.generate_documentation_for_action(this.subject, name);
            }
            /**
             * @author fenris
             */
            generate_documentation() {
                return api.generate_documentation(this.subject);
            }
        }
        api.class_api = class_api;
    })(api = lib_plankton.api || (lib_plankton.api = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:http«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:http« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:http« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:http«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var http;
    (function (http) {
        /**
         * @author fenris <frass@greenscale.de>
         */
        let enum_method;
        (function (enum_method) {
            enum_method["get"] = "get";
            enum_method["post"] = "post";
            enum_method["patch"] = "patch";
            enum_method["put"] = "put";
            enum_method["delete"] = "delete";
            enum_method["options"] = "options";
            enum_method["head"] = "head";
        })(enum_method = http.enum_method || (http.enum_method = {}));
    })(http = lib_plankton.http || (lib_plankton.http = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:http«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:http« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:http« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:http«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var http;
    (function (http) {
        /**
         * @author fenris <frass@greenscale.de>
         */
        const linebreak = "\r\n";
        /**
         * @todo outsource to string module
         */
        function capitalize(str) {
            return (str[0].toUpperCase() + str.slice(1));
        }
        /**
         * @todo outsource to string module
         */
        function capitalize_all(str) {
            return str.split("-").map(x => capitalize(x)).join("-");
        }
        /**
         * @author fenris <frass@greenscale.de>
         */
        function encode_method(method) {
            switch (method) {
                case http.enum_method.get: return "GET";
                case http.enum_method.post: return "POST";
                case http.enum_method.patch: return "PATCH";
                case http.enum_method.put: return "PUT";
                case http.enum_method.delete: return "DELETE";
                case http.enum_method.options: return "OPTIONS";
                case http.enum_method.head: return "HEAD";
                default: throw (new Error("impossible"));
            }
        }
        http.encode_method = encode_method;
        /**
         * @author fenris <frass@greenscale.de>
         */
        function decode_method(method_raw) {
            switch (method_raw) {
                case "GET": return http.enum_method.get;
                case "POST": return http.enum_method.post;
                case "PATCH": return http.enum_method.patch;
                case "PUT": return http.enum_method.put;
                case "DELETE": return http.enum_method.delete;
                case "OPTIONS": return http.enum_method.options;
                case "HEAD": return http.enum_method.head;
                default: throw (new Error("unhandled method: " + method_raw));
            }
        }
        /**
         * @author fenris <frass@greenscale.de>
         */
        function get_statustext(statuscode) {
            switch (statuscode) {
                case 100: return "Continue";
                case 101: return "Switching Protocols";
                case 103: return "Early Hints";
                case 200: return "OK";
                case 201: return "Created";
                case 202: return "Accepted";
                case 203: return "Non-Authoritative Information";
                case 204: return "No Content";
                case 205: return "Reset Content";
                case 206: return "Partial Content";
                case 300: return "Multiple Choices";
                case 301: return "Moved Permanently";
                case 302: return "Found";
                case 303: return "See Other";
                case 304: return "Not Modified";
                case 307: return "Temporary Redirect";
                case 308: return "Permanent Redirect";
                case 400: return "Bad Request";
                case 401: return "Unauthorized";
                case 402: return "Payment Required";
                case 403: return "Forbidden";
                case 404: return "Not Found";
                case 405: return "Method Not Allowed";
                case 406: return "Not Acceptable";
                case 407: return "Proxy Authentication Required";
                case 408: return "Request Timeout";
                case 409: return "Conflict";
                case 410: return "Gone";
                case 411: return "Length Required";
                case 412: return "Precondition Failed";
                case 413: return "Payload Too Large";
                case 414: return "URI Too Long";
                case 415: return "Unsupported Media Type";
                case 416: return "Range Not Satisfiable";
                case 417: return "Expectation Failed";
                case 418: return "I'm a teapot";
                case 422: return "Unprocessable Entity";
                case 425: return "Too Early";
                case 426: return "Upgrade Required";
                case 428: return "Precondition Required";
                case 429: return "Too Many Requests";
                case 431: return "Request Header Fields Too Large";
                case 451: return "Unavailable For Legal Reasons";
                case 500: return "Internal Server Error";
                case 501: return "Not Implemented";
                case 502: return "Bad Gateway";
                case 503: return "Service Unavailable";
                case 504: return "Gateway Timeout";
                case 505: return "HTTP Version Not Supported";
                case 506: return "Variant Also Negotiates";
                case 507: return "Insufficient Storage";
                case 508: return "Loop Detected";
                case 510: return "Not Extended";
                case 511: return "Network Authentication";
                default: throw (new Error("unhandled statuscode: " + statuscode.toFixed(0)));
            }
        }
        /**
         * @author fenris <frass@greenscale.de>
         */
        function encode_request(request) {
            let request_raw = "";
            request_raw += (encode_method(request.method)
                +
                    " "
                +
                    request.path
                +
                    ((request.query === null) ? "" : request.query)
                +
                    " "
                +
                    request.version
                +
                    linebreak);
            if (request.host === null) {
                // do nothing
            }
            else {
                request_raw += ("Host: " + request.host + linebreak);
            }
            for (const [key, value] of Object.entries(request.headers)) {
                request_raw += (capitalize_all(key) + ": " + value + linebreak);
            }
            request_raw += linebreak;
            if (request.body === null) {
                // do nothing
            }
            else {
                request_raw += request.body.toString();
            }
            return request_raw;
        }
        http.encode_request = encode_request;
        /**
         * @author fenris <frass@greenscale.de>
         */
        function decode_request(request_raw) {
            const lines = request_raw.split(linebreak);
            const first = lines.shift();
            const parts = first.split(" ");
            const method = decode_method(parts[0]);
            const path_and_query = parts[1];
            const parts_ = path_and_query.split("?");
            const path = parts_[0];
            const query = ((parts_.length <= 1) ? null : ("?" + parts_.slice(1).join("?")));
            const version = parts[2];
            let headers = {};
            while (true) {
                const line = lines.shift();
                if (line === "") {
                    break;
                }
                else {
                    const [key, value] = line.split(": ", 2);
                    headers[key.toLowerCase()] = value;
                }
            }
            const body = ([http.enum_method.get, http.enum_method.head, http.enum_method.options, http.enum_method.delete].includes(method)
                ? null
                : Buffer["from"](lines.join(linebreak)));
            const request = {
                // TODO
                "scheme": "http",
                "host": (headers["host"] ?? null),
                "path": path,
                "version": version,
                "method": method,
                "query": query,
                "headers": headers,
                "body": body,
            };
            return request;
        }
        http.decode_request = decode_request;
        /**
         * @author fenris <frass@greenscale.de>
         */
        function encode_response(response) {
            let response_raw = "";
            response_raw += (response.version
                +
                    " "
                +
                    response.status_code.toFixed(0)
                +
                    " "
                +
                    get_statustext(response.status_code)
                +
                    linebreak);
            for (const [key, value] of Object.entries(response.headers)) {
                response_raw += (capitalize_all(key) + ": " + value + linebreak);
            }
            response_raw += linebreak;
            response_raw += response.body;
            return response_raw;
        }
        http.encode_response = encode_response;
        /**
         * @author fenris <frass@greenscale.de>
         */
        function decode_response(response_raw) {
            const lines = response_raw.split(linebreak);
            const first = lines.shift();
            const first_parts = first.split(" ");
            const version = first_parts[0];
            const status_code = parseInt(first_parts[1]);
            // first_parts.slice(2) ? probably irrelevant
            let headers = {};
            while (true) {
                const line = lines.shift();
                if (line === "") {
                    break;
                }
                else {
                    const [key, value] = line.split(": ", 2);
                    headers[key.toLowerCase()] = value;
                }
            }
            const body = Buffer["from"](lines.join(linebreak));
            const response = {
                // TODO
                "version": version,
                "status_code": status_code,
                "headers": headers,
                "body": body,
            };
            return response;
        }
        http.decode_response = decode_response;
        /**
         * executes an HTTP request
         *
         * @todo define type_signal
         */
        async function call(request, options = {}) {
            options = Object.assign({
                "timeout": 5.0,
                "follow_redirects": false,
                "implementation": "fetch",
            }, options);
            const target = (request.scheme
                +
                    "://"
                +
                    request.host
                +
                    request.path
                +
                    ((request.query === null)
                        ? ""
                        : request.query));
            switch (options.implementation) {
                default: {
                    return Promise.reject("invalid implementation: " + options.implementation);
                    break;
                }
                case "fetch": {
                    function core(signal) {
                        return (fetch(target, {
                            "method": ((method => {
                                switch (method) {
                                    case http.enum_method.get: return "GET";
                                    case http.enum_method.post: return "POST";
                                    case http.enum_method.patch: return "PATCH";
                                    case http.enum_method.put: return "PUT";
                                    case http.enum_method.delete: return "DELETE";
                                    case http.enum_method.options: return "OPTIONS";
                                    case http.enum_method.head: return "HEAD";
                                }
                            })(request.method)),
                            "headers": request.headers,
                            "redirect": (options.follow_redirects ? "follow" : "manual"),
                            "signal": (signal ?? undefined),
                        })
                            .catch((reason) => {
                            console.info(reason);
                            return Promise.reject(reason);
                        })
                            .then((response_raw) => (response_raw.text()
                            .then((body) => Promise.resolve({
                            // TODO
                            "version": null,
                            "status_code": response_raw.status,
                            "headers": ((headers_raw => {
                                let headers = {};
                                headers_raw.forEach((value, key) => {
                                    headers[key] = value;
                                });
                                return headers;
                            })(response_raw.headers)),
                            "body": body,
                        })))));
                    }
                    function timeout(controller) {
                        return (new Promise((resolve, reject) => {
                            if (options.timeout === null) {
                                // do nothing (neither resolve nor reject ever)
                            }
                            else {
                                setTimeout(() => {
                                    controller.abort();
                                    resolve(null);
                                }, (options.timeout * 1000));
                            }
                        }));
                    }
                    const controller = new AbortController();
                    const signal = controller.signal;
                    const response = await Promise.race([
                        timeout(controller),
                        core(signal),
                    ]);
                    if (response === null) {
                        throw (new Error("http_request_timeout"));
                    }
                    else {
                        return response;
                    }
                    break;
                }
                case "http_module": {
                    const nm_http = require("http");
                    const nm_https = require("https");
                    return (new Promise((resolve, reject) => {
                        const req = ((request.scheme === "https")
                            ? nm_https
                            : nm_http)
                            .request(target, {
                            "method": request.method,
                            "headers": request.headers,
                        }, (res) => {
                            try {
                                let response_body = "";
                                res.setEncoding("utf8");
                                res.on("data", (chunk) => {
                                    response_body += chunk;
                                });
                                res.on("end", () => {
                                    resolve({
                                        // TODO
                                        "version": null,
                                        "status_code": res.statusCode,
                                        "headers": res.headers,
                                        "body": response_body,
                                    });
                                });
                            }
                            catch (error) {
                                reject(error);
                            }
                        });
                        req.on("error", (error) => {
                            reject(error);
                        });
                        req.write(request.body);
                        req.end();
                    }));
                    break;
                }
            }
        }
        http.call = call;
    })(http = lib_plankton.http || (lib_plankton.http = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:http«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:http« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:http« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:http«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var http;
    (function (http) {
        /**
         * @author fenris
         */
        class class_http_request {
            /**
             * @author fenris
             */
            constructor() {
            }
            /**
             * @implementation
             * @author fenris
             */
            encode(x) {
                return http.encode_request(x);
            }
            /**
             * @implementation
             * @author fenris
             */
            decode(x) {
                return http.decode_request(x);
            }
        }
        http.class_http_request = class_http_request;
        /**
         * @author fenris
         */
        class class_http_response {
            /**
             * @author fenris
             */
            constructor() {
            }
            /**
             * @implementation
             * @author fenris
             */
            encode(x) {
                return http.encode_response(x);
            }
            /**
             * @implementation
             * @author fenris
             */
            decode(x) {
                return http.decode_response(x);
            }
        }
        http.class_http_response = class_http_response;
    })(http = lib_plankton.http || (lib_plankton.http = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:rest«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:rest« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:rest« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:rest«. If not, see <http://www.gnu.org/licenses/>.
 */
/*
This file is part of »bacterio-plankton:rest«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:rest« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:rest« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:rest«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var rest;
    (function (rest_1) {
        /**
         */
        function http_request_method_to_oas(http_request_method) {
            switch (http_request_method) {
                case lib_plankton.http.enum_method.get: return "get";
                case lib_plankton.http.enum_method.post: return "post";
                case lib_plankton.http.enum_method.patch: return "patch";
                case lib_plankton.http.enum_method.head: return "put";
                case lib_plankton.http.enum_method.delete: return "delete";
                case lib_plankton.http.enum_method.options: return "options";
                case lib_plankton.http.enum_method.put: return "head";
                default: throw (new Error("impossible"));
            }
        }
        /**
         */
        function wildcard_step_decode(step) {
            const matches = (new RegExp("^:(.*)$")).exec(step);
            if ((matches === null) || (matches.length < 2)) {
                return null;
            }
            else {
                return matches[1];
            }
        }
        /**
         */
        function wildcard_step_encode(name) {
            return (":" + name);
        }
        /**
         */
        function routenode_iterate(routenode, procedure, steps) {
            procedure(routenode, steps);
            Object.entries(routenode.sub_branch).forEach(([key, value]) => {
                routenode_iterate(value, procedure, steps.concat([key]));
            });
            if (!(routenode.sub_wildcard === null)) {
                routenode_iterate(routenode.sub_wildcard.node, procedure, steps.concat([wildcard_step_encode(routenode.sub_wildcard.name)]));
            }
        }
        /**
         */
        function routenode_flatten(routenode) {
            let list = [];
            routenode_iterate(routenode, (routenode_, steps) => {
                list.push({ "steps": steps, "node": routenode_ });
            }, []);
            return list;
        }
        /**
         */
        function routenode_spawn(steps, http_method, operation) {
            let routenode;
            if (steps.length <= 0) {
                routenode = {
                    "operations": Object.fromEntries([[http_method, operation]]),
                    "sub_branch": {},
                    "sub_wildcard": null,
                };
            }
            else {
                const steps_head = steps[0];
                const steps_tail = steps.slice(1);
                const sub = routenode_spawn(steps_tail, http_method, operation);
                const wildcard_name = wildcard_step_decode(steps_head);
                if (wildcard_name === null) {
                    // branch
                    routenode = {
                        "operations": {},
                        "sub_branch": Object.fromEntries([[steps_head, sub]]),
                        "sub_wildcard": null,
                    };
                }
                else {
                    // wildcard
                    routenode = {
                        "operations": {},
                        "sub_branch": {},
                        "sub_wildcard": { "name": wildcard_name, "node": sub },
                    };
                }
            }
            return routenode;
        }
        /**
         */
        function routenode_path_read(routenode, steps) {
            if (steps.length <= 0) {
                return {
                    "steps": [],
                    "rest": [],
                    "routenode": routenode,
                    "parameters": {},
                };
            }
            else {
                const path_head = steps[0];
                const path_tail = steps.slice(1);
                if (path_head in routenode.sub_branch) {
                    const result = routenode_path_read(routenode.sub_branch[path_head], path_tail);
                    return {
                        "steps": [path_head].concat(result.steps),
                        "rest": result.rest,
                        "routenode": result.routenode,
                        "parameters": result.parameters,
                    };
                }
                else {
                    if (!(routenode.sub_wildcard === null)) {
                        const result = routenode_path_read(routenode.sub_wildcard.node, path_tail);
                        if (!(routenode.sub_wildcard.name in result.parameters)) {
                            // do nothing
                        }
                        else {
                            lib_plankton.log.warning("rest_overwriting_path_parameter", {
                                "key": routenode.sub_wildcard.name,
                                "value_old": result.parameters[routenode.sub_wildcard.name],
                                "value_new": path_head,
                            });
                        }
                        return {
                            "steps": [path_head].concat(result.steps),
                            "rest": result.rest,
                            "routenode": result.routenode,
                            "parameters": lib_plankton.object.patched(Object.fromEntries([[routenode.sub_wildcard.name, path_head]]), result.parameters),
                        };
                    }
                    else {
                        return {
                            "steps": [path_head],
                            "rest": path_tail,
                            "routenode": routenode,
                            "parameters": {},
                        };
                    }
                }
            }
        }
        /**
         */
        function routenode_path_write(routenode, steps, http_method, operation, options = {}) {
            options = lib_plankton.object.patched({
                "create": false,
            }, options);
            if (steps.length <= 0) {
                if (!(http_method in routenode.operations)) {
                    // do nothing
                }
                else {
                    lib_plankton.log.warning("rest_overwriting_action", {
                        "http_method": http_method,
                        "steps": steps,
                    });
                }
                routenode.operations[http_method] = operation;
            }
            else {
                const steps_head = steps[0];
                const steps_tail = steps.slice(1);
                const wildcard_name = wildcard_step_decode(steps_head);
                if (!(wildcard_name === null)) {
                    // wildcard
                    if (routenode.sub_wildcard === null) {
                        if (!options.create) {
                            throw (new Error("may not create missing route"));
                        }
                        else {
                            routenode.sub_wildcard = {
                                "name": wildcard_name,
                                "node": routenode_spawn(steps_tail, http_method, operation),
                            };
                        }
                    }
                    else {
                        if (!(routenode.sub_wildcard.name === wildcard_name)) {
                            /*
                            lib_plankton.log.warning(
                                "rest_overwriting_wildcard_node",
                                {
                                    "wildcard_name": wildcard_name,
                                }
                            );
                             */
                            throw (new Error("inconsistent wildcard name: '" + routenode.sub_wildcard.name + "' vs. '" + wildcard_name + "'"));
                        }
                        else {
                            // walk
                            routenode_path_write(routenode.sub_wildcard.node, steps_tail, http_method, operation, options);
                        }
                    }
                }
                else {
                    if (steps_head in routenode.sub_branch) {
                        // walk branch
                        routenode_path_write(routenode.sub_branch[steps_head], steps_tail, http_method, operation, options);
                    }
                    else {
                        // add branch
                        if (!options.create) {
                            throw (new Error("may not create missing route"));
                        }
                        else {
                            routenode.sub_branch[steps_head] = routenode_spawn(steps_tail, http_method, operation);
                        }
                    }
                }
            }
        }
        /**
         */
        function make(options = {}) {
            options = lib_plankton.object.patched({
                "title": "REST-API",
                "versioning_method": "none",
                "versioning_header_name": "X-Api-Version",
                "versioning_query_key": "version",
                "header_parameters": [],
                "set_access_control_headers": false,
                "authentication": {
                    "kind": "none",
                    "parameters": {},
                },
                "actions": [],
            }, options);
            const subject = {
                "api": lib_plankton.api.make(options.title),
                "versioning_method": options.versioning_method,
                "versioning_header_name": options.versioning_header_name,
                "versioning_query_key": options.versioning_query_key,
                "routetree": {
                    "operations": {},
                    "sub_branch": {},
                    "sub_wildcard": null,
                },
                "header_parameters": options.header_parameters,
                "set_access_control_headers": options.set_access_control_headers,
                "authentication": options.authentication,
            };
            options.actions.forEach(action_definition => {
                rest.register(subject, action_definition.http_method, action_definition.path, action_definition.options);
            });
            return subject;
        }
        rest_1.make = make;
        /**
         */
        function register(rest, http_method, path, options) {
            options = lib_plankton.object.patched({
                "active": ((version) => true),
                "execution": ((stuff) => Promise.resolve({ "status_code": 501, "data": null })),
                "restriction": ((stuff) => Promise.resolve(true)),
                "input_schema": ((version) => ({})),
                "output_schema": ((version) => ({})),
                "title": null,
                "description": null,
                "query_parameters": [],
                "request_body_mimetype": "application/json",
                "request_body_decode": ((http_request_body, http_request_header_content_type) => (((http_request_header_content_type !== null)
                    &&
                        (http_request_header_content_type.startsWith("application/json"))
                    &&
                        (http_request_body !== null)
                    &&
                        (http_request_body.toString() !== ""))
                    ? JSON.parse(http_request_body.toString())
                    : ((http_request_body !== null)
                        ? http_request_body.toString()
                        : null))),
                "response_body_mimetype": "application/json",
                // TODO: no "from"?
                "response_body_encode": ((output) => Buffer["from"](JSON.stringify(output))),
            }, options);
            const steps = lib_plankton.string.split(path, "/").slice(1);
            const steps_enriched = ((rest.versioning_method === "path")
                ? ["{version}"].concat(steps)
                : steps);
            const action_name = (steps.concat([lib_plankton.http.encode_method(http_method).toLowerCase()])
                .join("_"));
            const operation = {
                "action_name": action_name,
                "query_parameters": options.query_parameters,
                "request_body_mimetype": options.request_body_mimetype,
                "request_body_decode": options.request_body_decode,
                "response_body_mimetype": options.response_body_mimetype,
                "response_body_encode": options.response_body_encode,
                "input_schema": options.input_schema,
                "output_schema": options.output_schema,
            };
            routenode_path_write(rest.routetree, steps_enriched, http_method, operation, {
                "create": true,
            });
            lib_plankton.api.register(rest.api, action_name, {
                "active": options.active,
                "execution": (version, environment, input) => options.execution({
                    "version": version,
                    "path_parameters": environment.path_parameters,
                    "query_parameters": environment.query_parameters,
                    "headers": environment.headers,
                    "input": input
                }),
                "restriction": (version, environment) => options.restriction({
                    "version": version,
                    "path_parameters": environment.path_parameters,
                    "query_parameters": environment.query_parameters,
                    "headers": environment.headers,
                }),
                "title": options.title,
                "description": options.description,
                // TODO
                // "input_shape": options.input_type,
                // "output_shape": options.output_type,
            });
            lib_plankton.log.info("rest_route_added", {
                "http_method": http_method,
                "path": path,
                // "routetree": rest.routetree,
            });
        }
        rest_1.register = register;
        /**
         * @todo check request body mimetype?
         * @todo check query paramater validity
         */
        async function call(rest, http_request, options = {}) {
            options = /*lib_plankton.object.patched*/ Object.assign({
                "checklevel_restriction": lib_plankton.api.enum_checklevel.hard,
                "checklevel_input": lib_plankton.api.enum_checklevel.soft,
                "checklevel_output": lib_plankton.api.enum_checklevel.soft,
            }, options);
            lib_plankton.log.info("rest_call", {
                "http_request": {
                    "scheme": http_request.scheme,
                    "host": http_request.host,
                    "path": http_request.path,
                    "version": http_request.version,
                    "method": http_request.method,
                    "query": http_request.query,
                    "headers": http_request.headers,
                    "body": String(http_request.body),
                }
            });
            // parse target and query parameters
            // const url_stuff : URL = new URL("http://dummy" + http_request.target);
            const path = http_request.path;
            const query_parameters_raw = new URLSearchParams(http_request.query);
            let query_parameters = {};
            for (const [key, value] of query_parameters_raw) {
                query_parameters[key] = value;
            }
            const steps = lib_plankton.string.split(path, "/").slice(1);
            if (steps.length <= 0) {
                throw (new Error("empty path"));
            }
            else {
                // resolve
                const stuff = routenode_path_read(rest.routetree, steps);
                const allowed_methods = (Object.keys(stuff.routenode.operations)
                    .map(x => lib_plankton.http.encode_method(x))
                    .join(", "));
                // get version
                let version;
                switch (rest.versioning_method) {
                    case "none": {
                        version = null;
                        break;
                    }
                    case "path": {
                        version = stuff.parameters["version"];
                        // delete stuff.parameters["version"];
                        break;
                    }
                    case "header": {
                        version = http_request.headers[rest.versioning_header_name];
                        // delete http_request.headers[rest.versioning_header_name];
                        break;
                    }
                    case "query": {
                        version = query_parameters[rest.versioning_query_key];
                        // delete query_parameters[rest.versioning_query_key];
                        break;
                    }
                    default: {
                        throw (new Error("unhandled versioning method: " + rest.versioning_method));
                        break;
                    }
                }
                const additional_response_headers = (rest.set_access_control_headers
                    ? {
                        "Access-Control-Allow-Headers": (([
                            "Content-Type",
                            "X-Api-Key",
                        ]
                            .concat((rest.versioning_header_name !== null)
                            ? [rest.versioning_header_name]
                            : [])
                            .concat((rest.authentication.kind === "key_header")
                            ? [rest.authentication.parameters["name"]]
                            : []))
                            .join(", ")),
                        "Access-Control-Allow-Origin": "*",
                        "Access-Control-Allow-Methods": allowed_methods,
                    }
                    : {});
                if (stuff.rest.length > 0) {
                    return {
                        "version": "HTTP/1.1",
                        "status_code": 404,
                        "headers": {},
                        "body": null,
                    };
                }
                else {
                    if (http_request.method === lib_plankton.http.enum_method.options) {
                        return {
                            "version": "HTTP/1.1",
                            "status_code": 200,
                            "headers": Object.assign({}, additional_response_headers),
                            "body": null,
                        };
                    }
                    else {
                        if (!(http_request.method in stuff.routenode.operations)) {
                            if (Object.keys(stuff.routenode.operations).length <= 0) {
                                return {
                                    "version": "HTTP/1.1",
                                    "status_code": 404,
                                    "headers": Object.assign({}, additional_response_headers),
                                    "body": null,
                                };
                            }
                            else {
                                return {
                                    "version": "HTTP/1.1",
                                    "status_code": 405,
                                    "headers": Object.assign({
                                        "Allow": allowed_methods,
                                    }, additional_response_headers),
                                    "body": null,
                                };
                            }
                        }
                        else {
                            // call
                            let result;
                            let error;
                            const operation = stuff.routenode.operations[http_request.method];
                            const stuff_ = {
                                "version": version,
                                "headers": http_request.headers,
                                "path_parameters": stuff.parameters,
                                "query_parameters": query_parameters,
                                "input": ((http_request.body === null)
                                    ? null
                                    : operation.request_body_decode(http_request.body, (http_request.headers["Content-Type"]
                                        ??
                                            http_request.headers["content-type"]
                                        ??
                                            null))),
                            };
                            /*
                            const allowed : boolean = (
                                (operation.restriction === null)
                                ? true
                                : operation.restriction(stuff_)
                            );
                             */
                            let response;
                            /*
                            if (! allowed) {
                                lib_plankton.log.error(
                                    "rest_access_denied",
                                    {
                                        "http_request": {
                                            "target": http_request.target,
                                            "method": http_request.method,
                                            "headers": http_request.headers,
                                            "body": (
                                                (http_request.body === null)
                                                ? null
                                                : lib_plankton.string.limit(http_request.body.toString(), {"length": 200})
                                            ),
                                        },
                                    }
                                );
                                response = {
                                    "version": "HTTP/1.1",
                                    "status_code": 403,
                                    "headers": Object.assign(
                                        {
                                        },
                                        additional_response_headers
                                    ),
                                    "body": Buffer["from"]("forbidden"),
                                };
                            }
                            else*/ {
                                try {
                                    result = await lib_plankton.api.call(rest.api, operation.action_name, {
                                        "version": stuff_.version,
                                        "environment": {
                                            "headers": stuff_.headers,
                                            "path_parameters": stuff_.path_parameters,
                                            "query_parameters": stuff_.query_parameters,
                                        },
                                        "input": stuff_.input,
                                        "checklevel_restriction": options.checklevel_restriction,
                                        "checklevel_input": options.checklevel_input,
                                        "checklevel_output": options.checklevel_output,
                                    });
                                    error = null;
                                }
                                catch (error_) {
                                    result = null;
                                    error = error_;
                                }
                                if ((result === null) || (error !== null)) {
                                    if (error instanceof lib_plankton.api.class_error_permission_denied) {
                                        response = {
                                            "version": "HTTP/1.1",
                                            "status_code": 403,
                                            "headers": Object.assign({}, additional_response_headers),
                                            "body": null,
                                        };
                                    }
                                    else {
                                        lib_plankton.log.error("rest_execution_failed", {
                                            "http_request": {
                                                "version": http_request.version,
                                                "scheme": http_request.scheme,
                                                "method": http_request.method,
                                                "path": http_request.path,
                                                "query": http_request.query,
                                                "headers": http_request.headers,
                                                "body": ((http_request.body === null)
                                                    ? null
                                                    : lib_plankton.string.limit(http_request.body.toString(), { "length": 200 })),
                                            },
                                            "error": {
                                                "message": error.toString(),
                                                "file_name": error.fileName,
                                                "line_number": error.lineNumber,
                                                "stack": error.stack,
                                            },
                                        });
                                        response = {
                                            "version": "HTTP/1.1",
                                            "status_code": 500,
                                            "headers": Object.assign({}, additional_response_headers),
                                            "body": Buffer["from"]("internal error"),
                                        };
                                    }
                                }
                                else {
                                    // encode
                                    response = {
                                        "version": "HTTP/1.1",
                                        "status_code": result.status_code,
                                        "headers": Object.assign({
                                            "Content-Type": operation.response_body_mimetype,
                                        }, additional_response_headers),
                                        "body": operation.response_body_encode(result.data),
                                    };
                                }
                            }
                            return response;
                        }
                    }
                }
            }
        }
        rest_1.call = call;
        /**
         * @see https://swagger.io/specification/#openrest-object
         */
        function to_oas(rest, options = {}) {
            options = lib_plankton.object.patched({
                "version": null,
                "servers": [],
            }, options);
            const subject = rest;
            const version = (options.version ?? "-");
            return {
                "openapi": "3.0.3",
                "info": {
                    "version": version,
                    "title": (rest.api.title ?? "API"),
                    // "description": (rest.api.description ?? undefined),
                },
                "servers": options.servers.map(url => ({ "url": url })),
                "components": {
                    "securitySchemes": (((description) => ({
                        "none": {},
                        "key_header": {
                            "default_security_schema": {
                                "type": "restKey",
                                "in": "header",
                                "name": description.parameters["name"],
                            },
                        },
                    }[description.kind]))(rest.authentication)),
                },
                "security": [
                    {
                        "default_security_schema": [],
                    }
                ],
                "paths": lib_plankton.call.convey(rest.routetree, [
                    routenode_flatten,
                    (x) => x.map((entry) => {
                        const steps_ = entry.steps;
                        const path = lib_plankton.string.join(steps_, "_");
                        const key = ((steps_.length <= 0)
                            ? "/"
                            : lib_plankton.string.join([""].concat(steps_
                                .map(step => ((wildcard_step_decode(step) !== null)
                                ? ("{" + wildcard_step_decode(step) + "}")
                                : step))), "/"));
                        return [
                            key,
                            lib_plankton.call.convey(entry.node.operations, [
                                x => Object.entries(x),
                                (pairs) => pairs.map(([http_method, operation]) => ([
                                    http_request_method_to_oas(http_method),
                                    {
                                        "operationId": (http_request_method_to_oas(http_method)
                                            +
                                                "_"
                                            +
                                                path),
                                        "summary": (operation.title
                                            ??
                                                [""].concat(steps_).join(" ")),
                                        "description": (lib_plankton.api.get_action(rest.api, operation.action_name).description
                                            ??
                                                "(missing)"),
                                        "parameters": [].concat(
                                        // header parameters
                                        rest.header_parameters.map(header_parameter => ({
                                            "name": header_parameter.name,
                                            "in": "header",
                                            "required": header_parameter.required,
                                            "schema": {
                                                "type": "string",
                                            },
                                            "description": (header_parameter.description ?? undefined),
                                        })), 
                                        // path parameters
                                        lib_plankton.call.convey(steps_, [
                                            x => x.map(y => wildcard_step_decode(y)),
                                            x => x.filter(y => (!(y === null))),
                                            x => x.map(y => ({
                                                "name": y,
                                                "in": "path",
                                                "required": true,
                                                "schema": {
                                                    "type": "string",
                                                },
                                            })),
                                        ]), 
                                        // query parameters
                                        operation.query_parameters.map((query_parameter) => ({
                                            "name": query_parameter.name,
                                            "in": "query",
                                            "required": query_parameter.required,
                                            "schema": {
                                                "type": "string",
                                            },
                                            "description": (query_parameter.description ?? undefined),
                                        }))),
                                        "requestBody": (([
                                            lib_plankton.http.enum_method.get,
                                            lib_plankton.http.enum_method.head,
                                            lib_plankton.http.enum_method.delete,
                                        ].includes(http_method))
                                            ? undefined
                                            : {
                                                "content": Object.fromEntries([
                                                    [
                                                        operation.request_body_mimetype,
                                                        {
                                                            "schema": operation.input_schema(options.version),
                                                        }
                                                    ]
                                                ])
                                            }),
                                        "responses": {
                                            "default": {
                                                "description": "",
                                                "content": Object.fromEntries([
                                                    [
                                                        operation.response_body_mimetype,
                                                        {
                                                            "schema": operation.output_schema(options.version),
                                                        }
                                                    ]
                                                ]),
                                            }
                                        },
                                    }
                                ])),
                                (pairs) => Object.fromEntries(pairs),
                            ]),
                        ];
                    }),
                    x => x.filter(y => (Object.keys(y[1]).length > 0)),
                    x => Object.fromEntries(x),
                ])
            };
        }
        rest_1.to_oas = to_oas;
    })(rest = lib_plankton.rest || (lib_plankton.rest = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:server«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:server« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:server« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:server«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var server;
    (function (server) {
        /**
         * @author fenris
         */
        function make(port, handle) {
            return {
                "port": port,
                "handle": handle,
                "serverobj": undefined,
            };
        }
        server.make = make;
        /**
         * @author fenris
         */
        function start(subject) {
            const net = require("net");
            return (new Promise((resolve, reject) => {
                subject.serverobj = net.createServer((socket) => {
                    lib_plankton.log.info("server_client connected", {});
                    socket.on("readable", () => {
                        let chunk;
                        while (!((chunk = socket.read()) === null)) {
                            const input = chunk.toString();
                            lib_plankton.log.debug("server_reading", {
                                "input": input,
                            });
                            const metadata = {
                                "ip_address": socket.remoteAddress,
                            };
                            subject.handle(input, metadata)
                                .then((output) => {
                                lib_plankton.log.debug("server_writing", {
                                    "output": output,
                                });
                                socket.write(output);
                                socket.end();
                            })
                                .catch((error) => {
                                lib_plankton.log.warning("server_handle_failed", {
                                    "error": error.toString(),
                                });
                                // socket.write("");
                                socket.end();
                            });
                        }
                    });
                    socket.on("end", () => {
                        lib_plankton.log.info("server_client_disconnected", {});
                    });
                });
                subject.serverobj.on("error", (error) => {
                    // throw error;
                    process.stderr.write("net_error: " + String(error) + "\n\n");
                });
                subject.serverobj.listen(subject.port, () => {
                    lib_plankton.log.info("server_listenting", {
                        "port": subject.port,
                    });
                    resolve(undefined);
                });
            }));
        }
        server.start = start;
        /**
         * @author fenris
         */
        function kill(subject) {
            subject.serverobj.close();
            lib_plankton.log.info("server_stopped", {});
        }
        server.kill = kill;
    })(server = lib_plankton.server || (lib_plankton.server = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:server«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:server« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:server« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:server«. If not, see <common://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var server;
    (function (server) {
        /**
         * @author fenris
         */
        class class_server {
            /**
             * @author fenris
             */
            constructor(port, handle) {
                this.subject = server.make(port, handle);
            }
            /**
             * @author fenris
             */
            start() {
                return server.start(this.subject);
            }
            /**
             * @author fenris
             */
            kill() {
                return server.kill(this.subject);
            }
        }
        server.class_server = class_server;
    })(server = lib_plankton.server || (lib_plankton.server = {}));
})(lib_plankton || (lib_plankton = {}));
var lib_server = lib_plankton.server;
/*
This file is part of »bacterio-plankton:args«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:args« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:args« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:args«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var args;
    (function (args) {
        /**
         */
        var enum_environment;
        (function (enum_environment) {
            enum_environment["cli"] = "cli";
            enum_environment["url"] = "url";
        })(enum_environment = args.enum_environment || (args.enum_environment = {}));
        ;
        /**
         */
        var enum_kind;
        (function (enum_kind) {
            enum_kind["positional"] = "positional";
            enum_kind["volatile"] = "volatile";
        })(enum_kind = args.enum_kind || (args.enum_kind = {}));
        ;
        /**
         */
        var enum_type;
        (function (enum_type) {
            enum_type["boolean"] = "boolean";
            enum_type["integer"] = "int";
            enum_type["float"] = "float";
            enum_type["string"] = "string";
        })(enum_type = args.enum_type || (args.enum_type = {}));
        ;
        /**
         */
        var enum_mode;
        (function (enum_mode) {
            enum_mode["replace"] = "replace";
            enum_mode["accumulate"] = "accumulate";
        })(enum_mode = args.enum_mode || (args.enum_mode = {}));
        ;
    })(args = lib_plankton.args || (lib_plankton.args = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:args«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:args« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:args« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:args«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var args;
    (function (args) {
        /*
        export enum_mode {
            replace = "replace",
            accumulate = "accumulate",
        };
         */
        /**
         * @author fenris
         */
        var class_argument = /** @class */ (function () {
            /**
             * @author fenris
             */
            function class_argument(_a) {
                var name = _a["name"], _b = _a["type"], type = _b === void 0 ? args.enum_type.string : _b, _c = _a["kind"], kind = _c === void 0 ? args.enum_kind.positional : _c, _d = _a["mode"], mode = _d === void 0 ? args.enum_mode.replace : _d, _e = _a["default"], default_ = _e === void 0 ? null : _e, _f = _a["info"], info = _f === void 0 ? null : _f, _g = _a["parameters"], parameters = _g === void 0 ? {} : _g, _h = _a["hidden"], hidden = _h === void 0 ? false : _h;
                this.name = name;
                this.type = type;
                this.kind = kind;
                this.mode = mode;
                this.default_ = default_;
                this.info = info;
                this.parameters = parameters;
                this.hidden = hidden;
                if (!this.check()) {
                    throw (new Error("invalid argument-setup"));
                }
            }
            /**
             * @author fenris
             */
            class_argument.positional = function (_a) {
                var name = _a["name"], _b = _a["type"], type = _b === void 0 ? args.enum_type.string : _b, _c = _a["mode"], mode = _c === void 0 ? args.enum_mode.replace : _c, _d = _a["default"], default_ = _d === void 0 ? null : _d, _e = _a["info"], info = _e === void 0 ? null : _e, _f = _a["hidden"], hidden = _f === void 0 ? false : _f, index = _a["index"];
                return (new class_argument({
                    "name": name,
                    "kind": args.enum_kind.positional,
                    "type": type,
                    "mode": mode,
                    "default": default_,
                    "info": info,
                    "hidden": hidden,
                    "parameters": {
                        "index": index
                    }
                }));
            };
            /**
             * @author fenris
             */
            class_argument.volatile = function (_a) {
                var name = _a["name"], _b = _a["type"], type = _b === void 0 ? args.enum_type.string : _b, _c = _a["mode"], mode = _c === void 0 ? args.enum_mode.replace : _c, _d = _a["default"], default_ = _d === void 0 ? null : _d, _e = _a["info"], info = _e === void 0 ? null : _e, _f = _a["hidden"], hidden = _f === void 0 ? false : _f, indicators_short = _a["indicators_short"], indicators_long = _a["indicators_long"];
                return (new class_argument({
                    "name": name,
                    "kind": args.enum_kind.volatile,
                    "type": type,
                    "mode": mode,
                    "default": default_,
                    "info": info,
                    "hidden": hidden,
                    "parameters": {
                        "indicators_short": indicators_short,
                        "indicators_long": indicators_long
                    }
                }));
            };
            /**
             * @author fenris
             */
            class_argument.prototype.check = function () {
                var _this = this;
                return [
                    function () { return ((!(_this.kind == args.enum_kind.volatile))
                        ||
                            (("indicators_long" in _this.parameters)
                                &&
                                    (_this.parameters["indicators_long"]["length"] >= 0))); },
                ].every(function (condition) { return condition(); });
            };
            /**
             * @author fenris
             */
            class_argument.prototype.name_get = function () {
                return this.name;
            };
            /**
             * @author fenris
             */
            class_argument.prototype.kind_get = function () {
                return this.kind;
            };
            /**
             * @author fenris
             */
            class_argument.prototype.type_get = function () {
                return this.type;
            };
            /**
             * @author fenris
             */
            class_argument.prototype.mode_get = function () {
                return this.mode;
            };
            /**
             * @author fenris
             */
            class_argument.prototype.default_get = function () {
                return this.default_;
            };
            /**
             * @author fenris
             */
            class_argument.prototype.parameters_get = function () {
                return this.parameters;
            };
            /**
             * @author fenris
             */
            class_argument.prototype.hidden_get = function () {
                return this.hidden;
            };
            /**
             * @author fenris
             */
            class_argument.prototype.toString = function () {
                return "<".concat(this.name, ">");
            };
            /**
             * @author fenris
             */
            class_argument.prototype.indicator_main = function () {
                if (this.kind === args.enum_kind.volatile) {
                    return this.parameters["indicators_long"][0];
                }
                else {
                    return null;
                }
            };
            /**
             * @author fenris
             */
            class_argument.prototype.pattern_value = function () {
                switch (this.type) {
                    case args.enum_type.boolean: {
                        return "false|true";
                        break;
                    }
                    case args.enum_type.integer: {
                        return "[0-9]+";
                        break;
                    }
                    case args.enum_type.float: {
                        return "\\d*(?:\\.\\d+)?";
                        break;
                    }
                    case args.enum_type.string: {
                        return "\\S+";
                        break;
                    }
                    default: {
                        throw (new Error("unhandled type ".concat(this.type)));
                        break;
                    }
                }
            };
            /**
             * @author fenris
             */
            class_argument.prototype.extract = function (raw) {
                switch (this.type) {
                    case args.enum_type.boolean: {
                        return (raw != "false");
                        break;
                    }
                    case args.enum_type.integer: {
                        return parseInt(raw);
                        break;
                    }
                    case args.enum_type.float: {
                        return parseFloat(raw);
                        break;
                    }
                    case args.enum_type.string: {
                        return raw;
                        break;
                    }
                    default: {
                        throw (new Error("unhandled type ".concat(this.type)));
                        break;
                    }
                }
            };
            /**
             * @author fenris
             */
            class_argument.prototype.assign = function (data, target, raw) {
                var value = this.extract(raw);
                switch (this.mode) {
                    case args.enum_mode.replace: {
                        data[target] = value;
                        break;
                    }
                    case args.enum_mode.accumulate: {
                        /*
                        if (! (this.name in data)) {
                            data[this.name] = [];
                        }
                         */
                        data[target].push(value);
                        break;
                    }
                    default: {
                        throw (new Error("unhandled mode ".concat(this.mode)));
                    }
                }
            };
            /**
             * @author fenris
             */
            class_argument.prototype.make = function (data, target) {
                var value = data[target];
                return value.toString();
            };
            /**
             * @author fenris
             */
            class_argument.prototype.generate_help = function () {
                var _this = this;
                var _a, _b, _c, _d;
                var output = "";
                {
                    switch (this.kind) {
                        case args.enum_kind.positional: {
                            var line = "";
                            line += "\t";
                            line += "<".concat(this.name, ">");
                            line += "\n";
                            output += line;
                        }
                        case args.enum_kind.volatile: {
                            var line = "";
                            line += "\t";
                            if (this.type === args.enum_type.boolean) {
                                line += ([]
                                    .concat(((_a = this.parameters["indicators_short"]) !== null && _a !== void 0 ? _a : []).map(function (indicator) { return ("-" + indicator); }))
                                    .concat(((_b = this.parameters["indicators_long"]) !== null && _b !== void 0 ? _b : []).map(function (indicator) { return ("--" + indicator); }))
                                    .join(" | "));
                            }
                            else {
                                line += ([]
                                    .concat(((_c = this.parameters["indicators_short"]) !== null && _c !== void 0 ? _c : []).map(function (indicator) { return ("-" + indicator + " " + ("<" + _this.name + ">")); }))
                                    .concat(((_d = this.parameters["indicators_long"]) !== null && _d !== void 0 ? _d : []).map(function (indicator) { return ("--" + indicator + "=" + ("<" + _this.name + ">")); }))
                                    .join(" | "));
                            }
                            line += "\n";
                            output += line;
                        }
                    }
                }
                {
                    var line = "";
                    line += "\t\t";
                    var infotext = ((this.info == null) ? "(no info available)" : this.info);
                    line += infotext;
                    if ((this.type != "boolean") && (this.default_ != null)) {
                        line += "; default: ".concat(this.default_.toString());
                    }
                    line += "\n";
                    output += line;
                }
                return output;
            };
            return class_argument;
        }());
        args.class_argument = class_argument;
    })(args = lib_plankton.args || (lib_plankton.args = {}));
})(lib_plankton || (lib_plankton = {}));
/*
This file is part of »bacterio-plankton:args«.

Copyright 2016-2023 'Christian Fraß, Christian Neubauer, Martin Springwald GbR'
<info@greenscale.de>

»bacterio-plankton:args« is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

»bacterio-plankton:args« is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with »bacterio-plankton:args«. If not, see <http://www.gnu.org/licenses/>.
 */
var lib_plankton;
(function (lib_plankton) {
    var args;
    (function (args) {
        /**
         * @author fenris
         */
        var settings = {
            "environment": {
                "cli": {
                    "symbols": {
                        "delimiter": " ",
                        "prefix": "--",
                        "assignment": "="
                    }
                },
                "url": {
                    "symbols": {
                        "delimiter": "&",
                        "prefix": "",
                        "assignment": "="
                    }
                }
            }
        };
        /**
         * @author fenris
         */
        args.verbosity = 0;
        /**
         * @author fenris
         * @todo check validity
         */
        var class_handler = /** @class */ (function () {
            /**
             * @author fenris
             */
            function class_handler(arguments_) {
                this.arguments_ = arguments_;
            }
            /**
             * @author fenris
             */
            class_handler.prototype.filter = function (kind) {
                var arguments_ = {};
                for (var _i = 0, _a = Object.entries(this.arguments_); _i < _a.length; _i++) {
                    var _b = _a[_i], name = _b[0], argument = _b[1];
                    if (argument.kind_get() == kind) {
                        arguments_[name] = argument;
                    }
                }
                return arguments_;
            };
            /**
             * @author fenris
             */
            class_handler.prototype.read = function (environment, input, data) {
                var _this = this;
                if (data === void 0) { data = {}; }
                switch (environment) {
                    case args.enum_environment.cli:
                    case args.enum_environment.url: {
                        // default values
                        {
                            for (var _i = 0, _a = Object.entries(this.arguments_); _i < _a.length; _i++) {
                                var _b = _a[_i], name = _b[0], argument = _b[1];
                                data[name] = argument.default_get();
                            }
                        }
                        // preprocessing
                        {
                            // short indicators (lil hacky ...)
                            {
                                if (environment == args.enum_environment.cli) {
                                    for (var _c = 0, _d = Object.entries(this.filter(args.enum_kind.volatile)); _c < _d.length; _c++) {
                                        var _e = _d[_c], name = _e[0], argument = _e[1];
                                        // console.info(argument.parameters_get()["indicators_short"].join("|"));
                                        var pattern_from = "";
                                        {
                                            pattern_from += "(?:^|".concat(settings["environment"][environment]["symbols"]["delimiter"], ")");
                                            pattern_from += "-".concat(argument.parameters_get()["indicators_short"].join("|"));
                                            pattern_from += "(?:$|".concat(settings["environment"][environment]["symbols"]["delimiter"], ")");
                                        }
                                        var pattern_to = "";
                                        {
                                            pattern_to += settings["environment"][environment]["symbols"]["delimiter"];
                                            pattern_to += settings["environment"][environment]["symbols"]["prefix"];
                                            pattern_to += argument.indicator_main();
                                            if (argument.type_get() == args.enum_type.boolean) {
                                                pattern_to += settings["environment"][environment]["symbols"]["delimiter"];
                                            }
                                            else {
                                                pattern_to += settings["environment"][environment]["symbols"]["assignment"];
                                            }
                                        }
                                        var result = input.replace(new RegExp(pattern_from, "g"), pattern_to);
                                        lib_plankton.log.debug("lib_args:read:replacing", {
                                            "pattern_from": pattern_from,
                                            "pattern_to": pattern_to,
                                            "input": input,
                                            "result": result
                                        });
                                        input = result;
                                    }
                                }
                            }
                            lib_plankton.log.debug("lib_args:read:current_input", {
                                "input": input
                            });
                        }
                        // parsing
                        {
                            var parts = input
                                .split(settings["environment"][environment]["symbols"]["delimiter"])
                                .filter(function (x) { return (x != ""); });
                            var index_expected_1 = 0;
                            parts.forEach(function (part) {
                                lib_plankton.log.debug("lib_args:read:analyzing", {
                                    "part": part
                                });
                                var found = [
                                    function () {
                                        lib_plankton.log.debug("lib_args:read:probing_as_volatile", {
                                            "part": part
                                        });
                                        for (var _i = 0, _a = Object.entries(_this.filter(args.enum_kind.volatile)); _i < _a.length; _i++) {
                                            var _b = _a[_i], name = _b[0], argument = _b[1];
                                            lib_plankton.log.debug("lib_args:read:probing_as_volatile:trying", {
                                                "part": part,
                                                "argument": argument.toString()
                                            });
                                            var pattern = "";
                                            {
                                                var pattern_front = "";
                                                pattern_front += "".concat(settings["environment"][environment]["symbols"]["prefix"]);
                                                pattern_front += "(?:".concat(argument.parameters_get()["indicators_long"].join("|"), ")");
                                                pattern += pattern_front;
                                            }
                                            {
                                                var pattern_back = "";
                                                pattern_back += "".concat(settings["environment"][environment]["symbols"]["assignment"]);
                                                pattern_back += "(".concat(argument.pattern_value(), ")");
                                                if (argument.type_get() == args.enum_type.boolean) {
                                                    pattern_back = "(?:".concat(pattern_back, ")?");
                                                }
                                                pattern += pattern_back;
                                            }
                                            lib_plankton.log.debug("lib_args:read:probing_as_volatile:pattern", {
                                                "pattern": pattern
                                            });
                                            var regexp = new RegExp(pattern);
                                            var matching = regexp.exec(part);
                                            lib_plankton.log.debug("lib_args:read:probing_as_volatile:matching", {
                                                "matching": matching
                                            });
                                            if (matching == null) {
                                                // do nothing
                                            }
                                            else {
                                                argument.assign(data, name, matching[1]);
                                                return true;
                                            }
                                        }
                                        return false;
                                    },
                                    function () {
                                        lib_plankton.log.debug("lib_args:read:probing_as_positional", {
                                            "part": part
                                        });
                                        var positional = _this.filter(args.enum_kind.positional);
                                        for (var _i = 0, _a = Object.entries(positional); _i < _a.length; _i++) {
                                            var _b = _a[_i], name = _b[0], argument = _b[1];
                                            if (argument.parameters_get()['index'] !== index_expected_1) {
                                                // do nothing
                                            }
                                            else {
                                                lib_plankton.log.debug("lib_args:read:probing_as_positional:trying", {
                                                    "part": part,
                                                    "argument": argument.toString()
                                                });
                                                var pattern = "";
                                                {
                                                    var pattern_back = "";
                                                    pattern_back += "(".concat(argument.pattern_value(), ")");
                                                    pattern += pattern_back;
                                                }
                                                lib_plankton.log.debug("lib_args:read:probing_as_positional:pattern", {
                                                    "pattern": pattern
                                                });
                                                var regexp = new RegExp(pattern);
                                                var matching = regexp.exec(part);
                                                lib_plankton.log.debug("lib_args:read:probing_as_positional:matching", {
                                                    "matching": matching
                                                });
                                                if (matching == null) {
                                                    return false;
                                                }
                                                else {
                                                    argument.assign(data, name, matching[1]);
                                                    index_expected_1 += 1;
                                                    return true;
                                                }
                                            }
                                        }
                                        return false;
                                    },
                                ].some(function (x) { return x(); });
                                if (!found) {
                                    lib_plankton.log.warning("lib_args:read:could_not_parse", {
                                        "part": part
                                    });
                                }
                            });
                        }
                        return data;
                        break;
                    }
                    default: {
                        throw (new Error("unhandled environment ".concat(environment)));
                        break;
                    }
                }
            };
            /**
             * @author fenris
             * @todo handle if the data object doesn't have the required field or the type is wrong or sth.
             */
            class_handler.prototype.write = function (environment, data) {
                switch (environment) {
                    case args.enum_environment.cli: {
                        return (([]
                            .concat(Object.entries(this.filter(args.enum_kind.volatile)).map(function (_a) {
                            var name = _a[0], argument = _a[1];
                            var values;
                            switch (argument.mode_get()) {
                                case args.enum_mode.replace: {
                                    values = [data[argument.name_get()]];
                                    break;
                                }
                                case args.enum_mode.accumulate: {
                                    values = data[argument.name_get()];
                                    break;
                                }
                            }
                            return (values
                                .map(function (value) { return ((settings["environment"][environment]["symbols"]["prefix"]
                                +
                                    argument.parameters_get()["indicators_long"][0])
                                +
                                    (settings["environment"][environment]["symbols"]["assignment"]
                                        +
                                            value.toString())); })
                                .join(" "));
                        }))
                            .concat(Object.entries(this.filter(args.enum_kind.positional)).map(function (_a) {
                            var name = _a[0], argument = _a[1];
                            var raw = "";
                            {
                                var raw_back = "";
                                raw_back += argument.make(data, name);
                                raw += raw_back;
                            }
                            return raw;
                        })))
                            .join(settings["environment"][environment]["symbols"]["delimiter"]));
                        break;
                    }
                    default: {
                        throw (new Error("unhandled environment ".concat(environment)));
                        break;
                    }
                }
            };
            /**
             * @desc manpage-like info-sheet
             * @author fenris
             */
            class_handler.prototype.generate_help = function (_a) {
                var _b = _a["programname"], programname = _b === void 0 ? null : _b, _c = _a["author"], author = _c === void 0 ? null : _c, _d = _a["description"], description = _d === void 0 ? null : _d, _e = _a["executable"], executable = _e === void 0 ? null : _e;
                var environment = args.enum_environment.cli;
                var output = "";
                {
                    var section = "";
                    {
                        var line = "";
                        line += "";
                        line += "INFO";
                        line += "\n";
                        section += line;
                    }
                    {
                        var line = "";
                        line += "\t";
                        line += "".concat(programname, " -- ").concat(description);
                        line += "\n";
                        section += line;
                    }
                    section += "\n";
                    output += section;
                }
                {
                    if (author != null) {
                        var section = "";
                        {
                            var line = "";
                            line += "";
                            line += "AUTHOR";
                            line += "\n";
                            section += line;
                        }
                        {
                            var line = "";
                            line += "\t";
                            line += "".concat(author);
                            line += "\n";
                            section += line;
                        }
                        section += "\n";
                        output += section;
                    }
                }
                {
                    var section = "";
                    {
                        var line = "";
                        line += "";
                        line += "SYNOPSIS";
                        line += "\n";
                        section += line;
                    }
                    {
                        var line = "";
                        line += "\t";
                        line += executable;
                        line += settings["environment"][environment]["symbols"]["delimiter"];
                        line += Object.entries(this.filter(args.enum_kind.positional))
                            .map(function (_a) {
                            var name = _a[0], argument = _a[1];
                            var part = "";
                            part += "<".concat(argument.name_get(), ">");
                            return part;
                        })
                            .join(settings["environment"][environment]["symbols"]["delimiter"]);
                        line += settings["environment"][environment]["symbols"]["delimiter"];
                        line += Object.entries(this.filter(args.enum_kind.volatile))
                            .filter(function (_a) {
                            var name = _a[0], argument = _a[1];
                            return (!argument.hidden_get());
                        })
                            .map(function (_a) {
                            var name = _a[0], argument = _a[1];
                            var part = "";
                            // part += settings["environment"][environment]["symbols"]["prefix"];
                            part += "-";
                            part += argument.parameters_get()["indicators_short"][0];
                            if (argument.type_get() != "boolean") {
                                /*
                                part += settings["environment"][environment]["symbols"]["assignment"];
                                part += `<${argument.name_get()}>`;
                                 */
                                part += " ";
                                part += "<".concat(argument.name_get(), ">");
                            }
                            part = "[".concat(part, "]");
                            return part;
                        })
                            .join(settings["environment"][environment]["symbols"]["delimiter"]);
                        line += "\n";
                        section += line;
                    }
                    section += "\n";
                    output += section;
                }
                {
                    var section = "";
                    {
                        var line = "";
                        line += "";
                        line += "OPTIONS";
                        line += "\n";
                        section += line;
                    }
                    {
                        section += (Object.entries(this.arguments_)
                            .filter(function (_a) {
                            var name = _a[0], argument = _a[1];
                            return (!argument.hidden_get());
                        })
                            .map(function (_a) {
                            var name = _a[0], argument = _a[1];
                            return argument.generate_help();
                        })
                            .join("\n"));
                    }
                    section += "\n";
                    output += section;
                }
                return output;
            };
            return class_handler;
        }());
        args.class_handler = class_handler;
    })(args = lib_plankton.args || (lib_plankton.args = {}));
})(lib_plankton || (lib_plankton = {}));
