Source: index.js

// #region  F I L E
// <copyright file="mcode-data/index.js" company="MicroCODE Incorporated">Copyright © 2022-2024 MicroCODE, Inc. Troy, MI</copyright><author>Timothy J. McGuire</author>
// #region  M O D U L E
// #region  D O C U M E N T A T I O N
/**
 *      Project:  MicroCODE MERN Applications
 *      Customer: Internal + MIT xPRO Course
 *      @module   'mcode-data.js'
 *      @memberof mcode
 *      @created  January 2022-2024
 *      @author   Timothy McGuire, MicroCODE, Inc.
 *      @description >
 *      MicroCODE Common Data Utitlities
 *
 *      LICENSE:
 *      --------
 *      MIT License: MicroCODE.mcode-data
 *
 *      Copyright (c) 2022-2025 Timothy McGuire, MicroCODE, Inc.
 *
 *      Permission is hereby granted, free of charge, to any person obtaining a copy
 *      of this software and associated documentation files (the "Software"), to deal
 *      in the Software without restriction, including without limitation the rights
 *      to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 *      copies of the Software, and to permit persons to whom the Software is
 *      furnished to do so, subject to the following conditions:
 *
 *      The above copyright notice and this permission notice shall be included in all
 *      copies or substantial portions of the Software.
 *
 *      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *      OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 *      SOFTWARE.
 *
 *
 *      DESCRIPTION:
 *      ------------
 *      This module implements the MicroCODE's Common JavaScript functions for data handling.
 *
 *
 *      REFERENCES:
 *      -----------
 *      1. MIT xPRO Course: Professional Certificate in Coding: Full Stack Development with MERN.
 *
 *      2. LADDERS® source code: MACRO-11, MACRO-32, C#, and JavaScript.
 *
 *
 *
 *
 *      MODIFICATIONS:
 *      --------------
 *      Date:         By-Group:   Rev:    Description:
 *
 *      30-Jan-2024   TJM-MCODE  {0001}   New module for common reusable JavaScript data handling functions.
 *      01-Feb-2024   TJM-MCODE  {0002}   Changed to the Universal Module Definition (UMD) pattern to support AMD,
 *                                        CommonJS/Node.js, and browser global in our exported module.
 *      01-Feb-2024   TJM-MCODE  {0003}   Swap() and Call() now throw an error if the 'keys' and 'values' lists are not the same length,
 *                                        instead of logging the error and returning a default value.
 *      22-Aug-2024   TJM-MCODE  {0004}   Corrected isJson() to rely on 1st character being '{' to determine JSON string
 *                                        it was returning true for any string that contained a '{' character,
 *                                        this was signaling 'true' for HTMX templates that contained '{{variable}}'.
 *      05-Oct-2024   TJM-MCODE  {0005}   Added 'uuidDecode()' function to decode UUID strings into their component parts.
 *
 *      19-Feb-2025   TJM-MCODE  {0006}   v0.5.08 - updated 'httpStatus()' to use a STATIC copy of HTTP codes JSON for speed.
 *                                                - updated all UUID string lists to STATIC as well.
 *      17-Apr-2025   TJM-MCODE  {0007}   v0.5.09 - added 'isHtml()' function to check if a string is HTML,
 *                                                  updated 'isJson()' to use same check.
 *      23-Oct-2025   TJM-MCODE  {0008}   v0.6.03 - added 'classExport()' to return the created class constructor to support SSR
 *                                                  and ESM module loading, especially in HTMX applications.
 *                                                  Also added: sleep(), ifNumber(), encodeJson(), generateRandomId().
 *
 *
 *
 * NOTE: This module follows MicroCODE's JavaScript Style Guide and Template JS file, see:
 *
 *       o  https://github.com/MicroCODEIncorporated/JavaScriptSG
 *       o  https://github.com/MicroCODEIncorporated/TemplatesJS
 *
 */

// #endregion

// #region  I M P O R T S

// #endregion

// #region  T Y P E S

// #endregion

// #region  I N T E R F A C E S

// #endregion

// #region  C O N S T A N T S, F U N C T I O N S – P U B L I C

// MicroCODE: define this module's name for our 'mcode-log' package
const MODULE_NAME = 'mcode-data.js';

// Static copy of HTTP codes for httpStatus() function for speed - {0006}
const HTTP_CODES =
{
    //1xx: Informational responses (CYAN)
    "100": "Continue",
    "101": "Switching Protocols",
    "102": "Processing",
    "103": "Early Hints",
    "104": "Checkpoint (WebDAV)",
    "105": "Switch Proxy (WebDAV)",
    "106": "Processing (WebDAV)",
    "107": "Handoff (WebDAV)",

    //2xx: Success responses (GREEN)
    "200": "OK",  // for READ
    "201": "Created",  //for CREATE
    "202": "Accepted",  // for PUT/PATCH/DELETE
    "203": "Non-Authoritative Information",
    "204": "No Content",
    "205": "Reset Content",
    "206": "Partial Content",
    "207": "Multi-Status",
    "208": "Already Reported",
    "226": "IM Used",

    //3xx: Redirection responses (YELLOW)
    "300": "Multiple Choices",
    "301": "Moved Permanently",
    "302": "Found",
    "303": "See Other",
    "304": "Not Modified",
    "305": "Use Proxy",
    "307": "Temporary Redirect",
    "308": "Permanent Redirect",
    "309": "Resume Incomplete (WebDAV)",
    "310": "Too Many Redirects",

    //4xx: Client error responses (RED)
    "400": "Bad Request",  // missing Record Fields during CREATE or PUT
    "401": "Unauthorized",
    "402": "Payment Required",
    "403": "Forbidden",
    "404": "Not Found",  // no record to update during PATCH or PUT
    "405": "Method Not Allowed",
    "406": "Not Acceptable",
    "407": "Proxy Authentication Required",
    "408": "Request Timeout",
    "409": "Conflict",
    "410": "Gone",
    "411": "Length Required",
    "412": "Precondition Failed",
    "413": "Payload Too Large",
    "414": "URI Too Long",
    "415": "Unsupported Media Type",
    "416": "Range Not Satisfiable",
    "417": "Expectation Failed",
    "418": "I'm a Teapot", // indicates that the server refuses to brew coffee because it is a teapot. (An April fool’s joke from 1998)
    "419": "Page Expired (Laravel)",
    "421": "Misdirected Request",
    "422": "Unprocessable Entity",
    "423": "Locked",
    "424": "Failed Dependency",
    "425": "Too Early",
    "426": "Upgrade Required",
    "428": "Precondition Required",
    "429": "Too Many Requests",
    "431": "Request Header Fields Too Large",
    "440": "Login Timeout (Microsoft)",
    "444": "Connection Closed Without Response (NGINX)",
    "449": "Retry With (Microsoft - IIS specific)",
    "450": "Blocked by Windows Parental Controls (Microsoft)",
    "451": "Unavailable For Legal Reasons",
    "499": "Client Closed Request (NGINX)",

    //5xx: Server error responses (MAGENTA)
    "500": "Internal Server Error",  // unexpected Code Exceptions
    "501": "Not Implemented",  // hit stubs or calls to non-existent endpoints
    "502": "Bad Gateway",
    "503": "Service Unavailable",
    "504": "Gateway Timeout",
    "505": "HTTP Version Not Supported",
    "506": "Variant Also Negotiates",
    "507": "Insufficient Storage",
    "508": "Loop Detected",
    "509": "Bandwidth Limit Exceeded (Apache/cPanel)",
    "510": "Not Extended",
    "511": "Network Authentication Required",
    "520": "Unknown Error (Cloudflare)",
    "521": "Web Server Is Down (Cloudflare)",
    "522": "Connection Timed Out (Cloudflare)",
    "523": "Origin Is Unreachable (Cloudflare)",
    "524": "A Timeout Occurred (Cloudflare)",
    "525": "SSL Handshake Failed (Cloudflare)",
    "526": "Invalid SSL Certificate (Cloudflare)",
    "527": "Railgun Error (Cloudflare)",
    "530": "Origin DNS Error (Cloudflare-FTP)",
    "598": "Network Read Timeout Error (Unofficial)",
    "599": "Network Connect Timeout Error (Azure/AWS)",
};

// U U I D - V A R I A N T S

const UUID_VARIANTS = [
    "NCS compatibility",
    "NCS compatibility",
    "RFC 4122, RFC 9562",
    "Microsoft GUIDs",
];

// U U I D - V E R S I O N S

// NCS compatibility (variant 0, 1)
const UUID_VAR1_VERSIONS = [
    "Undefined / Reserved / NIL",     // 0
    " NCS Security Version",          // 1
    " NCS Security Version",          // 2
    " NCS Security Version",          // 3
    " NCS Security Version",          // 4
    " NCS Security Version",          // 5
    " NCS Security Version",          // 6
    " NCS Security Version",          // 7
    " NCS Security Version",          // 8
    " NCS Security Version",          // 9
    " NCS Security Version",          // 10
    " NCS Security Version",          // 11
    " NCS Security Version",          // 12
    " NCS Security Version",          // 13
    " NCS Security Version",          // 14
    "Undefined / Reserved / MAX",     // 15
];

// RFC 4122 (Leach-Salz) (variant 2)
const UUID_VAR2_VERSIONS = [
    "Undefined / Reserved / NIL",     // 0
    "Gregorian Unordered Timestamp",  // 1
    "DCE Security (POSIX)",           // 2
    "Name-Based (MD5 Hash)",          // 3
    "Random-Based Number",            // 4
    "Name Based (SHA-1 Hash)",        // 5
    "Gregorian Ordered Timestamp",    // 6
    "Unix Epoch Timestamp",           // 7
    "Custom Encoding Format",         // 8
    "Reserved for future defnition",  // 9
    "Reserved for future defnition",  // 10
    "Reserved for future defnition",  // 11
    "Reserved for future defnition",  // 12
    "Reserved for future defnition",  // 13
    "Reserved for future defnition",  // 14
    "Undefined / Reserved / MAX",     // 15
];

// Microsoft GUIDs (variant 3)
const UUID_VAR3_VERSIONS = [
    "Undefined / Reserved / NIL",     // 0
    "Microsoft GUID Version 1",       // 1
    "Microsoft GUID Version 2",       // 2
    "Microsoft GUID Version 3",       // 3
    "Microsoft GUID Version 4",       // 4
    "Microsoft GUID Version 5",       // 5
    "Microsoft GUID Version 6",       // 6
    "Microsoft GUID Version 7",       // 7
    "Microsoft GUID Version 8",       // 8
    "Microsoft GUID Version 9",       // 9
    "Microsoft GUID Version 10",      // 10
    "Microsoft GUID Version 11",      // 11
    "Microsoft GUID Version 12",      // 12
    "Microsoft GUID Version 13",      // 13
    "Microsoft GUID Version 14",      // 14
    "Undefined / Reserved / MAX",     // 15
];

/**
 * @namespace mcode
 * @desc mcode namespace containing functions and constants.
 */
const mcode = {

    /**
     * @func property
     * @memberof mcode
     * @desc Creates a property with get, set methods, validator, and on change events.
     * @api public
     * @param {object} options optional params to define the property
     * {initial: value, readonly: boolean, immutable: boolean, validator: function, onChange: function}.
     * @returns {object} a property object with get, set, type, reset, isReadOnly, and isImmutable methods.
     */
    property: function (options = {})
    {
        // internal variables
        const _initial = options?.initial;
        const _readonly = options.readonly || false;
        const _immutable = options.immutable || false;

        // optional functions
        const _validator = options.validator || function () {return true;};
        const _onChange = options.onChange || function () {};

        // the actual value of the property
        let _value = options.initial || undefined;

        return {
            get: function ()
            {
                return _value;
            },
            set: function (value)
            {
                if (_immutable && (_value !== undefined))
                {
                    throw new Error('「mcode.property」 This property is immutable.');
                }
                if (_readonly)
                {
                    throw new Error('「mcode.property」 This property is read-only.');
                }
                if (_validator(value))
                {
                    const _last = _value;
                    _value = value;
                    _onChange(_last, _value);
                }
                else
                {
                    throw new Error('「mcode.property」 Invalid property value.');
                }
            },
            type: function ()
            {
                return typeof _value;
            },
            reset: function ()
            {
                const _last = _value;
                _value = _initial;
                _onChange(_last, _value);
            },
            isReadOnly: function ()
            {
                return _readonly;
            },
            isImmutable: function ()
            {
                return _immutable;
            },
            hasChanged: function ()
            {
                return _value !== _initial;
            }
        };
    },

    /**
     * @func getProperty
     * @memberof mcode
     * @api private
     * @desc Safely resolve a nested property using an array of keys.
     * @param {object} source - Root object from which to read.
     * @param {Array<string>} path - Ordered list of keys to traverse.
     * @returns {any} Resolved value or undefined when not found.
     */
    getProperty: function (source, path)
    {
        return path.reduce((keyPath, key) =>
        {
            if (keyPath && Object.prototype.hasOwnProperty.call(keyPath, key))
            {
                return keyPath[key];
            }
            return undefined;
        }, source);
    },

    /**
     * @func setProperty
     * @memberof mcode
     * @desc Assign a nested property on the target object, creating scopes as needed.
     * @api private
     * @param {object} target - Object receiving the assignment.
     * @param {Array<string>} path - Ordered list of keys to reach the leaf property.
     * @param {any} value - Value to assign at the terminal path segment.
     * @returns {void}
     */
    setProperty: function (target, path, value)
    {
        let current = target;

        for (let index = 0; index < path.length - 1; index += 1)
        {
            const key = path[index];

            if (!current[key] || typeof current[key] !== 'object')
            {
                current[key] = {};
            }

            current = current[key];
        }

        current[path[path.length - 1]] = value;
    },

    /**
     * @func contextProperty
     * @memberof mcode
     * @desc Define a getter/setter proxy that syncs instance properties to context paths.
     * @api public
     * @param {Class} instance - Class instance being updated, must have a 'context' object and 'syncDomContext()' method.
     * @param {string} property - Property name exposed on the instance.
     * @param {Array<string>} path - Path segments within the context object.
     * @param {object} [options] - Optional configuration flags.
     * @param {boolean} [options.sync=true] - Whether to resync the DOM context when setting.
     * @returns {void}
     */
    contextProperty: function (instance, property, path, options = {})
    {
        const {sync = true} = options;

        if (!instance || typeof instance !== 'object')
        {
            throw new Error('[mcode] Invalid instance provided to contextProperty.');
        }
        if (!instance.syncDomContext || typeof instance.syncDomContext !== 'function')
        {
            throw new Error('[mcode] Invalid syncDomContext() method provided to contextProperty.');
        }
        if (!instance.context || typeof instance.context !== 'object')
        {
            throw new Error('[mcode] Invalid context object provided to contextProperty.');
        }

        Object.defineProperty(instance, property, {
            configurable: true,
            enumerable: false,
            get()
            {
                return mcode.getProperty(instance?.context, path);
            },
            set(value)
            {
                mcode.setProperty(instance?.context, path, value);
                if (sync)
                {
                    instance?.syncDomContext();
                }
            }
        });
    },

    /**
     * @func isString
     * @memberof mcode
     * @desc Checks whether or not a object is a JS String.
     * @api public
     * @param {object} jsObject JavaScript object to be tested
     * @returns {boolean} a value indicating whether or not the object is a STRING.
     */
    isString: function (jsObject)
    {
        return Object.prototype.toString.call(jsObject) === '[object String]';
    },

    /**
     * @method isObject
     * @memberof mcode
     * @desc Checks whether or not a object is a JS Object.
     * @api public
     * @param {object} jsObject JavaScript object to be tested
     * @returns {boolean} a value indicating whether or not the object is an OBJECT.
     */
    isObject: function (jsObject)
    {
        if (mcode.isString(jsObject)) return false;

        return typeof jsObject === 'object' && jsObject !== null && !Array.isArray(jsObject) && typeof jsObject !== 'function';
    },

    /**
     * @method isArray
     * @memberof mcode
     * @desc Checks whether or not an object is a JS Array.
     * @api public
     * @param {object} jsObject JavaScript object to be tested
     * @returns {boolean} a value indicating whether or not the object is an ARRAY.
     */
    isArray: function (jsObject)
    {
        return Array.isArray(jsObject);
    },

    /**
     * @method isFunction
     * @memberof mcode
     * @desc Checks whether or not an object is a JS Function.
     * @api public
     * @param {object} jsObject JavaScript object to be tested
     * @returns {boolean} a value indicating whether or not the object is a FUNCTION.
     */
    isFunction: function (jsObject)
    {
        if (mcode.isString(jsObject)) return false;

        return typeof jsObject === 'function';
    },

    /**
     * @func isNumber
     * @memberof mcode
     * @desc Checks whether or not an object is a JS Number and *not* NaN.
     * @api public
     * @param {any} numberToCheck as a number of some type
     * @returns {boolean} a value indicating whether or not the object is valid Number.
     */
    isNumber: function (numberToCheck)
    {
        // NOTE: this compare will fail for NaN
        // eslint-disable-next-line no-self-compare
        return (typeof numberToCheck === 'number') && (numberToCheck === numberToCheck);
    },

    /**
     * @function ifNumber
     * @memberof mcode
     * @desc Checks if a value is a valid number; if not, returns a default value.
     * @param {number} value The value to check.
     * @param {number} defaultValue The default value to return if the check fails.
     * @returns {number} The original value if valid, otherwise the default value.
     */
    ifNumber: function (value, defaultValue = 0)
    {
        return Number.isFinite(value) ? value : defaultValue;
    },

    /**
     * @func isNaN
     * @memberof mcode
     * @desc Checks whether or not an object is a double-precision 'Not-a-Number (Nan)'.
     * @api public
     * @param {any} numberToCheck as a number of some type
     * @returns {boolean} a value indicating whether or not the object is NaN.
     */
    isNaN: function (numberToCheck)
    {
        // NOTE: this compare will always be true for NaN, and only for NaN
        // eslint-disable-next-line no-self-compare
        return (numberToCheck !== numberToCheck);
    },

    /**
     * @func isJson
     * @memberof mcode
     * @desc Quickly checks a string for embedded JSON data.
     * @api public
     * @param {object} object string to be tested
     * @returns {boolean} a value indicating whether or not the object is a JSON string.
     */
    isJson: function (object)
    {
        try
        {
            if (typeof object !== 'string') return false;

            // if this string begins with '{' and ends with '}' its very likely legal JSON code
            const trimmed = object.trim();

            return trimmed.startsWith('{') && trimmed.endsWith('}');
        }
        catch
        {
            return false;  // *not* JSON and not parsable
        }
    },

    /**
     * @func isHtml
     * @memberof mcode
     * @desc Quickly checks a string for HTML content.
     * @api public
     * @param {object} object string to be tested
     * @returns {boolean} a value indicating whether or not the object is HTML string.
     */
    isHtml: function (object)
    {
        try
        {
            if (typeof object !== 'string') return false;

            // if this string begins with '<' and ends with '>' its very likely legal HTML code
            const trimmed = object.trim();

            return trimmed.startsWith('<') && trimmed.endsWith('>');
        }
        catch
        {
            return false;  // *not* HTML and not parsable
        }
    },

    /**
     * @func isDomAvailable
     * @memberof mcode
     * @desc Determine whether DOM APIs are available in the current environment.
     * @api public
     * @returns {boolean} True when document access is supported.
     */
    isDomAvailable: function ()
    {
        return typeof document !== 'undefined' && typeof document.getElementById === 'function';
    },

    /**
     * @func isUndefined
     * @memberof mcode
     * @desc Checks whether or not an object is a 'undefined'.
     * @api public
     * @param {any} objectToCheck as a variable of some type
     * @returns {boolean} a value indicating whether or not the object is UNDEFINED.
     */
    isUndefined: function (objectToCheck)
    {
        // return true if 'objectToCheck' is UNDEFINED or NULL
        return ((typeof objectToCheck === 'undefined') || (objectToCheck === null));
    },

    /**
     * @func isDate
     * @memberof mcode
     * @desc Checks whether or not an object is a JS Date.
     * @param {object} objectToCheck
     * @returns {boolean} a value indicating whether or not the object is a DATE.
     */
    isDate: function (objectToCheck)
    {
        // return true if 'objectToCheck' is DATE Value
        return (objectToCheck instanceof Date);
    },

    /**
     * @func isTimeStamp
     * @memberof mcode
     * @desc Checks whether or not an object is a Timestampe, i.e.: a JS Date.
     * @param {object} objectToCheck
     * @returns {boolean} a value indicating whether or not the object is a TIMESTAMP.
     */
    isTimeStamp: function (objectToCheck)
    {
        // return true if 'objectToCheck' is DATE/TIMESTAMP Value
        return (objectToCheck instanceof Date);
    },

    /**
     * @func octify
     * @memberof mcode
     * @desc Converts a string to an octal string.
     * @api public
     * @param {string} text - The string to be converted to an octal string of bytes.
     * @returns {string} The octal string.
     * @example
     *           mcode.octify('Hello, World!');  // returns: "110 145 154 154 157 54 40 127 157 162 154 144 41"
     */
    octify(text)
    {
        const buffer = Buffer.from(text, 'utf8');

        // Convert each byte to its octal representation
        const octArray = [...buffer].map((byte) => byte.toString(8).padStart(3, '0'));

        // Join the octal values into a string separated by spaces
        return octArray.join(' ');
    },

    /**
     * @func hexify
     * @memberof mcode
     * @desc Converts a string to a hexadecinal string of bytes.
     * @api public
     * @param {string} text the string to be converted to a hex string.
     * @returns {string} the hex string.
     * @example
     *           mcode.hexify('Hello, World!');  // returns: "48 65 6c 6c 6f 2c 20 57 6f 72 6c 64 21"
     */
    hexify(text)
    {
        const buffer = Buffer.from(text, 'utf8');
        const hex = buffer.toString('hex');

        // Format the hex string into groups of 2 characters (1 byte)
        return hex.match(/.{1,2}/g).join(' ');
    },

    /**
     * @func default
     * @memberof mcode
     * @desc Evaluates a param and returns a default if the param is null, undefined,
     * or empty (strings, arrays, objects, or primitives).
     * @api public
     * @param {any} anyItem The JavaScript entity being tested.
     * @param {any} defaultItem The item to be returned if 'anyItem' is null, undefined, or empty.
     * @returns {any} The original item or the default if empty/null/undefined.
     * @example
     *     err = mcode.default(err, 'Undefined error occurred');  // default to recognizable message
     *     data = mcode.default(data, []); // Default to empty array
     *     config = mcode.default(config, {}); // Default to empty object
     *     count = mcode.default(count, 1); // Default to 1 if count is 0
     *
     *     log(mcode.default(undefined, 'Default'));   // 'Default'
     *     log(mcode.default(null, 'Default'));        // 'Default'
     *     log(mcode.default('', 'Default'));          // 'Default'
     *     log(mcode.default(0, 1));                   // 1 (0 is 'empty', returns default)
     *     log(mcode.default(42, 1));                  // 42 (non-zero number, returns original)
     *     log(mcode.default([], []));                 // []
     *     log(mcode.default(['item'], ['default']));  // ['item']
     *     log(mcode.default({}, {}));                 // {}
     *     log(mcode.default({ key: 'value' }, { def: 'default' }));
     *                                                        // { key: 'value' }
     *     log(mcode.default(true, false));            // true
     *     log(mcode.default('Hello', 'Default'));     // 'Hello'
     */
    default(anyItem, defaultItem)
    {
        // handle null, undefined, or empty values
        if (anyItem === null || anyItem === undefined)
        {
            return defaultItem;
        }

        // handle empty strings
        if (typeof anyItem === 'string' && anyItem === '')
        {
            return defaultItem;
        }

        // handle unassigned values (0 is treated as 'unassigned')
        if (typeof anyItem === 'number' && anyItem === 0)
        {
            return defaultItem;
        }

        // handle empty arrays
        if (Array.isArray(anyItem) && anyItem.length === 0)
        {
            return defaultItem;
        }

        // Handle empty objects (excluding null prototypes or non-object types)
        if (typeof anyItem === 'object' && anyItem !== null && Object.keys(anyItem).length === 0)
        {
            return defaultItem;
        }

        // return the original item for all other cases (primitives, non-empty arrays/objects, etc.)
        return anyItem;
    },

    /**
     * @func extractId
     * @memberof mcode
     * @desc Extracts an alpha-numberic ID Field from a string, intended to be a unique portion of a common string.
     * @param {string} objectName typically a file name, but can be any string, to extract an ID Field from.
     * @returns {string} the extracted ID Field.
     *
     * @example
    *
     *  Rules for extracting the ID Field:
     *
     *  1. The ID Field is assumed to be the first alpha-numeric field in the string.
     *  2. The ID Field is assumed to be Letters + Numbers, with no spaces or special characters.
     *  3. The ID Field is assumed to be either at the beginning or end of the string, or separated by non-alpha-numeric characters.
     *  4. The ID Field could have lowercase 'placeholders' for numbers, like 'PxCy' or 'PnCn' for 'P1C2'.
     *
     * const str1 = "CG_BRKE01_20231116.L5K";
     * const str2 = "CG_BRKE03_20231116.L5K";
     *
     *  log(extractIdField(str1));     // Expected output: "BRKE01"
     *  log(extractIdField(str2));     // Expected output: "BRKE03"
     *
     * const str1 = "EP_GPT13TZ1_20231115_0800.L5K";
     * const str2 = "EP_GPT13TZ2_20231113_1600.L5K";
     *
     *  log(extractIdField(str1));     // Expected output: "GPT13TZ1"
     *  log(extractIdField(str2));     // Expected output: "GPT13TZ2"
     *
     * const str1 = "SEP_P1C2_GMP_ARL.L5K";
     * const str2 = "SEP_P3C0_GMP_ARL.L5K";
     *
     *  log(extractIdField(str1));     // Expected output: "P1C2"
     *  log(extractIdField(str2));     // Expected output: "P3C0"
     *
     * const str1 = "SEP_P1C2_GMP_ARL.L5K";
     * const str2 = "SEP_PxCy_GMP.L5K";
     *
     *  log(extractIdField(str1));     // Expected output: "P1C2"
     *  log(extractIdField(str2));     // Expected output: "PxCy"
     *
     */
    extractId: function (objectName)
    {
        let idField = '';
        let inAlphaNumeric = false;
        let isLetter = false;
        let isLowerL = false;
        let isNumber = false;
        let hasLetters = false;
        let hasNumbers = false;
        let si = 0;

        // ƒ to check for upper case letter
        const isUpper = (objectName, i) =>
        {
            // if 'i' is outside 'objectName' return false
            if (i < 0 || i >= objectName.length)
            {
                return false;
            }
            return (objectName[i] >= 'A' && objectName[i] <= 'Z');
        };

        // scan the string for the first alpha-numeric field
        for (let i = 0; i < objectName.length; i++)
        {
            isNumber = (objectName[i] >= '0' && objectName[i] <= '9');
            isLetter = (objectName[i] >= 'A' && objectName[i] <= 'Z');
            isLowerL = (objectName[i] >= 'a' && objectName[i] <= 'z');

            if (isNumber || isLetter || isLowerL)
            {
                if (!inAlphaNumeric)
                {
                    inAlphaNumeric = true;
                    si = i;
                }
                idField += objectName[i];
                hasLetters = hasLetters || isLetter || isLowerL;
                hasNumbers = hasNumbers || isNumber;

                // Check for 'lower case numeric placeholder' like 'PxCy' or 'PnCn' for 'P1C2'
                if (isUpper(objectName, i - 1) && isUpper(objectName, i + 1) && isLowerL)
                {
                    hasNumbers = true;  // treat the single lower case letter between upper case letters as a number placeholder
                }
            }
            else
            {
                // hit non Alpha-Numeric character
                if (inAlphaNumeric && hasLetters && hasNumbers)
                {
                    idField = objectName.substring(si, i);
                    break;  // we have the field we want, exit to return it
                }
                else
                {
                    // current field does not meet criteria, reset and continue
                    si = 0;
                    idField = '';
                    inAlphaNumeric = false;
                    hasLetters = false;
                    hasNumbers = false;
                }
            }
        }

        return idField || '';
    },

    /**
     * @func httpStatus
     * @memberof mcode
     * @desc Returns the text for a given HTTP status code.
     * @param {var} httpCode the HTTP status code to translate.
     * @returns {string} a value representing the English meaning of a HTTP status code, formatted for display.
     */
    httpStatus: function (httpCode)
    {
        // return the translated HTTP status code
        // example: `[HTTP] 404: Not Found`
        return (`[HTTP] ${httpCode}: ` + HTTP_CODES[httpCode] || 'Unknown HTTP Status');
    },

    /**
     * @func httpSeverity
     * @memberof mcode
     * @desc Returns the mcode.log() severity (as text) for a given HTTP status code.
     * @param {var} httpCode the HTTP status code to translate.
     * @returns {string} a value representing the text name for logging the proper severity.
     */
    httpSeverity: function (httpCode)
    {
        if (httpCode >= 500)
        {
            return 'fatal';  // these severity must match mcode.log() definitions and app-banner.module.css
        }
        else if (httpCode >= 400)
        {
            return 'error';
        }
        else if (httpCode >= 300)
        {
            return 'warning';
        }
        else if (httpCode >= 200)
        {
            return 'success';
        }
        else if (httpCode >= 100)
        {
            return 'info';
        }
        return 'none';
    },

    /**
     * @func uuidDecode
     * @memberof mcode
     * @desc Decodes a UUID string into its component parts, this supports RFC 4122 and RFC 9562 UUIDs.
     * @param {string} uuid a UUID string in the format 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
     * @param {boolean} localTime a flag to indicate if the timestamp should be converted to local time for display.
     * @returns {string} a JSON object containing the decoded UUID parts.
     */
    uuidDecode: function (uuid, localTime = false)
    {
        // L I S T S - by UUID Variant and their Versions

        // ƒ Table of UUID Variants
        const uuidVariants = [
            uuidvar1,  // NCS compatibility
            uuidvar1,  // NCS compatibility
            uuidvar2,  // RFC 4122, RFC 9562
            uuidvar3,  // Microsoft GUIDs
        ];

        // ƒ Table of UUID Layouts for Variant #0/1 (NCS compatibility)
        const uuidvar1Layouts = [
            uuidvarNIL,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvar1reserved,
            uuidvarMAX,
        ];

        // ƒ Table of UUID Layouts for Variant #2 (RFC 4122, RFC 9562)
        const uuidvar2Layouts = [
            uuidvarNIL,
            uuidvar2v1,
            uuidvar2v2,
            uuidvar2v3,
            uuidvar2v4,
            uuidvar2v5,
            uuidvar2v6,
            uuidvar2v7,
            uuidvar2v8,
            uuidvar2reserved,
            uuidvar2reserved,
            uuidvar2reserved,
            uuidvar2reserved,
            uuidvar2reserved,
            uuidvar2reserved,
            uuidvarMAX
        ];

        // ƒ Table of UUID Layouts for Variant #3 (GUID)
        const uuidvar3Layouts = [
            uuidvarNIL,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvar3reserved,
            uuidvarMAX,
        ];

        // L A Y O U T S - by UUID Variant and their Versions

        // ƒ UUID Variant #0 and #1 - NCS compatibility
        function uuidvar1()
        {
            versionText = UUID_VAR1_VERSIONS[version];
            return uuidvar1Layouts[version]();
        }

        // ƒ UUID Variant #2 - RFC 4122 (Leach-Salz)
        function uuidvar2()
        {
            versionText = UUID_VAR2_VERSIONS[version];
            return uuidvar2Layouts[version]();
        }

        // ƒ UUID Variant #3 - Microsoft GUIDs
        function uuidvar3()
        {
            versionText = UUID_VAR3_VERSIONS[version];
            return uuidvar3Layouts[version]();
        }

        // V E R S I O N S - by UUID Variant

        // ƒ UUIDvar*v0 - Unused / Reserved for 00000000-0000-0000-0000-000000000000
        function uuidvarNIL()
        {
            // decoded by default as a generic UUID

            return uuidGenericLayout();
        }

        // ƒ UUIDvar*v15 - Unused / Reserved for FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF
        function uuidvarMAX()
        {
            // decoded by default as a generic UUID

            return uuidGenericLayout();
        }

        // ƒ UUIDv1, UUIDv1 - 14 - Unused /  reserved UUID variants
        function uuidvar1reserved()
        {
            // decoded by default as a generic UUID

            return uuidGenericLayout();
        }

        // ƒ UUIDv2, UUIDv9-15 - Unused /  reserved UUID variants
        function uuidvar2reserved()
        {
            // decoded by default as a generic UUID

            return uuidGenericLayout();
        }

        // D E C O D E R S - by UUID Variant and their Versions

        // ƒ to build a timestamp string in the format "YYYY-MMM-DD HH:MM:SS.mmm.uuu UTC"
        function makeTimestamp(time_high, time_mid, time_low, epochInMs, localTime, version)
        {
            try
            {
                // Handle UUID version 1 (time-based)
                const timeHigh = BigInt(parseInt(time_high, 16));
                const timeMid = BigInt(parseInt(time_mid, 16));
                const timeLow = BigInt(parseInt(time_low, 16));
                let timeValue, timeValueInMs, millisecondsSinceEpoch, timeDate;

                switch (version)
                {
                    case 1:
                        // Combine the time fields into a 60-bit value using BigInt
                        timeValue = (timeHigh << 48n) | (timeMid << 32n) | timeLow;
                        // UUID uses 100-nanosecond intervals, so we convert the timeValue to milliseconds
                        timeValueInMs = timeValue / 10000n;
                        // Add time since UUID epoch to the precomputed epoch offset
                        millisecondsSinceEpoch = Number(timeValueInMs + epochInMs);
                        // Convert to a JavaScript Date object
                        timeDate = new Date(millisecondsSinceEpoch);
                        break;
                    case 6:
                        // Combine the time fields into a 60-bit value using BigInt
                        timeValue = (timeHigh << 28n) | (timeMid << 12n) | timeLow;
                        // UUID uses 100-nanosecond intervals, so we convert the timeValue to milliseconds
                        timeValueInMs = timeValue / 10000n;
                        // Add time since UUID epoch to the precomputed epoch offset
                        millisecondsSinceEpoch = Number(timeValueInMs + epochInMs);
                        // Convert to a JavaScript Date object
                        timeDate = new Date(millisecondsSinceEpoch);
                        break;
                    case 7:
                        // Combine the 48-bit timestamp from the first two fields
                        timeValue = (timeHigh << 16n) | timeLow;
                        // Convert the Unix timestamp (milliseconds since Unix epoch)
                        timeDate = new Date(Number(timeValue));
                        break;
                    default:
                        // Combine the time fields into a 60-bit value using BigInt
                        timeValue = 0;
                        break;
                }

                // Extract milliseconds and microseconds
                const milliseconds = timeDate.getMilliseconds();
                const microseconds = (version === 7) ? 0 : Number((timeValue % 10000n) / 10n);

                if (localTime)
                {
                    // Format the value to "YYYY-MMM-DD HH:MM:SS.mmm.uuu AM/PM"
                    const datePart = timeDate.toLocaleDateString('en-US', {year: 'numeric', month: 'short', day: '2-digit'});
                    const timePart = timeDate.toLocaleTimeString('en-US', {
                        hour: '2-digit',
                        minute: '2-digit',
                        second: '2-digit',
                        hour12: true
                    });
                    const ampm = timePart.slice(-2); // AM/PM part
                    const timeNoMeridian = timePart.slice(0, -3); // Time without AM/PM
                    timestampText = `${datePart} ${timeNoMeridian}.${milliseconds.toString().padStart(3, '0')}.${microseconds.toString().padStart(3, '0')} ${ampm}`;
                }
                else
                {
                    // Format the value to "YYYY-MMM-DD HH:MM:SS.mmm.uuu UTC"
                    timestampText = timeDate.toISOString()
                        .replace('T', ' ')
                        .replace('Z', '')
                        .replace(/\.\d{3}/, `.${milliseconds.toString().padStart(3, '0')}.${microseconds.toString().padStart(3, '0')} UTC`);
                }
            }
            catch
            {
                // If there is an error, return the raw timestamp
                timestampText = `${time_high}${time_mid}${time_low} - decode error`;
            }
            return timestampText;
        }

        // ƒ UUIDv1 - Unordered Time-based UUID
        function uuidvar2v1()
        {
            /*
             UUIDv1 Field and Bit Layout - Gregorian Unordered Time-based UUID:
             3             2               1               0               0
             1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
            +---------------+---------------+---------------+---------------+
            |                         time_low                              |
            +---------------+---------------+--------+------+---------------+
            |            time_mid           |   ver  |     time_high        |
            ----+-----------+---------------+--------+------+---------------+
            |var|        clock_seq          |            node               |
            +---+-----------+---------------+---------------+---------------+
            |                            node                               |
            +---------------+---------------+---------------+---------------+
            */

            const time_low = part_a1;
            const time_mid = part_a0;
            const time_high = part_b;
            const time = `${time_high}${time_mid}${time_low}`;
            const clock_seq = part_c2;
            const clockSeq = BigInt(parseInt(clock_seq, 16));
            const node = part_c1 + part_c0;

            // Determine if the node is multicast based on the first bit of 'node'
            const multicastBit = parseInt(node.substring(0, 1), 16) >> 3;  // Extract multicast flag (1 bit) from node
            const multicast = multicastBit === 1;
            const multicastText = multicast ? 'Multicast' : 'Unicast';

            // The reset is based on UUID Variant and the Version of that Variant...
            let nodeType;
            let nodeValue;

            // Multicast or Unicast Addressed node
            nodeType = multicast ? 'MAC Address (Multicast)' : 'MAC Address (Unicast)';
            nodeValue = node.match(/.{2}/g).join(':');

            // The epoch is October 15, 1582 (start of UUID time)
            const epochInMs = BigInt(Date.UTC(1582, 9, 15));

            // Get 'YYYY-MMM-DD HH:MM:SS.mmm.uuu UTC'
            const timestampText = makeTimestamp(time_high, time_mid, time_low, epochInMs, localTime, 1);

            // Return Variant 2 UUIDv1 Decoded
            return {

                UUID: uuid,

                Variant: variant,
                VariantText: variantText,

                Version: version,
                VersionText: versionText,

                Value1Name: "Timestamp",
                Value1: timestampText,

                Value2Name: "Clock Sequence",
                Value2: clockSeq,

                Value3Name: "",
                Value3: "",

                Value4Name: "Node Type",
                Value4: nodeType,

                Value5Name: "Node Address",
                Value5: `${nodeValue}`,

                Value6Name: "",
                Value6: "",

                NumberName: "Random Number",
                NumberText: `0x${time_high}${time_mid}${time_low}`,

                time_low: time_low,
                time_mid: time_mid,
                time_high: time_high,
                time: time,
                clock_seq: clock_seq,
                multicast: multicast,
                multicastText: multicastText,
                node: node,
                macid: nodeValue
            };
        }

        // ƒ UUIDv2 - DCE Security (POSIX) UUID
        function uuidvar2v2()
        {
            /*
             UUIDv2 Field and Bit Layout -  DCE Security (POSIX) UUID:
             3             2               1               0               0
             1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
            +---------------+---------------+---------------+---------------+
            |                         part_a1                               |
            +---------------+---------------+--------+------+---------------+
            |            part_a0            |   ver  |     part_b           |
            ----+-----------+---------------+--------+------+---------------+
            |var|        part_c2            |            part_c1            |
            +---+-----------+---------------+---------------+---------------+
            |                            part_c0                            |
            +---------------+---------------+---------------+---------------+
            */

            // {TBD} - not documented in RFC 9562

            return uuidGenericLayout();
        }

        // ƒ UUIDv3 - Name-Based (MD5 Hash) UUID
        function uuidvar2v3()
        {
            /*
             UUIDv3 Field and Bit Layout - Name-Based (MD5 Hash) UUID:
             3             2               1               0               0
             1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
            +---------------+---------------+---------------+---------------+
            |                         md5_high_1                            |
            +---------------+---------------+--------+------+---------------+
            |            md5_high_0         |   ver  |     md5_mid          |
            ----+-----------+---------------+--------+------+---------------+
            |var|        md5_low_2          |            md5_low_1          |
            +---+-----------+---------------+---------------+---------------+
            |                            md5_low_0                          |
            +---------------+---------------+---------------+---------------+
            */

            const md5_high_1 = part_a1;
            const md5_high_0 = part_a0;
            const md5_high = `${md5_high_1}${md5_high_0}`;
            const md5_mid = part_b;
            const md5_low_2 = part_c2;
            const md5_low_1 = part_c1;
            const md5_low_0 = part_c0;
            const md5_low = `${md5_low_2}${md5_low_1}${md5_low_0}`;

            const md5 = `${md5_high}${md5_mid}${md5_low}`;

            // Return Variant 2 UUIDv1 Decoded
            return {

                UUID: uuid,

                Variant: variant,
                VariantText: variantText,

                Version: version,
                VersionText: versionText,

                Value1Name: "md5_high",
                Value1: md5_high,

                Value2Name: "md5_mid",
                Value2: md5_mid,

                Value3Name: "md5_low",
                Value3: md5_low,

                Value4Name: "",
                Value4: '',

                Value5Name: "",
                Value5: '',

                Value6Name: "",
                Value6: '',

                NumberName: "MD5 Hash",
                NumberText: `0x${md5}`,

                md5_high: md5_high,
                md5_mid: md5_mid,
                md5_low: md5_low,

                MD5: md5
            };
        }

        // ƒ UUIDv4 - Random-Based Number UUID
        function uuidvar2v4()
        {
            /*
             UUIDv4 Field and Bit Layout - Random-Based Number UUID:
             3             2               1               0               0
             1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
            +---------------+---------------+---------------+---------------+
            |                        random_a1                              |
            +---------------+---------------+--------+------+---------------+
            |            random_a0          |   ver  |     random_b         |
            ----+-----------+---------------+--------+------+---------------+
            |var|        random_c2          |            random_c1          |
            +---+-----------+---------------+---------------+---------------+
            |                            part_c0                            |
            +---------------+---------------+---------------+---------------+
            */

            const random_a1 = part_a1;
            const random_a0 = part_a0;
            const random_a = `${random_a1}${random_a0}`;
            const random_b = part_b;
            const random_c2 = part_c2;
            const random_c1 = part_c1;
            const random_c0 = part_c0;
            const random_c = `${random_c2}${random_c1}${random_c0}`;

            const random = `${random_a}${random_b}${random_c}`;

            // Return Variant 2 UUIDv1 Decoded
            return {

                UUID: uuid,

                Variant: variant,
                VariantText: variantText,

                Version: version,
                VersionText: versionText,

                Value1Name: "random_a",
                Value1: random_a,

                Value2Name: "random_b",
                Value2: random_b,

                Value3Name: "random_c",
                Value3: random_c,

                Value4Name: "",
                Value4: '',

                Value5Name: "",
                Value5: '',

                Value6Name: "",
                Value6: '',

                NumberName: "Random Number",
                NumberText: `0x${random}`,

                random_a: random_a,
                random_b: random_b,
                random_c: random_c,

                Random: random
            };
        }

        // ƒ UUIDv5 - Name Based (SHA-1 Hash) UUID
        function uuidvar2v5()
        {
            /*
             UUIDv5 Field and Bit Layout -  Name Based (SHA-1 Hash) UUID:
             3             2               1               0               0
             1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
            +---------------+---------------+---------------+---------------+
            |                         sha1_high_1                           |
            +---------------+---------------+--------+------+---------------+
            |            sha1_high_0        |   ver  |     sha1_mid         |
            ----+-----------+---------------+--------+------+---------------+
            |var|        sha1_low_2         |            sha1_low_1         |
            +---+-----------+---------------+---------------+---------------+
            |                            sha1_low_0                         |
            +---------------+---------------+---------------+---------------+
            */

            const sha1_high_1 = part_a1;
            const sha1_high_0 = part_a0;
            const sha1_high = `${sha1_high_1}${sha1_high_0}`;
            const sha1_mid = part_b;
            const sha1_low_2 = part_c2;
            const sha1_low_1 = part_c1;
            const sha1_low_0 = part_c0;
            const sha1_low = `${sha1_low_2}${sha1_low_1}${sha1_low_0}`;

            const sha1 = `${sha1_high}${sha1_mid}${sha1_low}`;

            // Return Variant 2 UUIDv1 Decoded
            return {

                UUID: uuid,

                Variant: variant,
                VariantText: variantText,

                Version: version,
                VersionText: versionText,

                Value1Name: "sha1_high",
                Value1: sha1_high,

                Value2Name: "sha1_mid",
                Value2: sha1_mid,

                Value3Name: "sha1_low",
                Value3: sha1_low,

                Value4Name: "",
                Value4: '',

                Value5Name: "",
                Value5: '',

                Value6Name: "",
                Value6: '',

                NumberName: "SHA-1 Hash",
                NumberText: `0x${sha1}`,

                sha1_high: sha1_high,
                sha1_mid: sha1_mid,
                sha1_low: sha1_low,

                "SHA-1": sha1
            };
        }

        // ƒ UUIDv6 - Gregorian Ordered Timestamp UUID
        function uuidvar2v6()
        {
            /*
             UUIDv6 Field and Bit Layout - Gregorian Ordered Timestamp UUID:
             3             2               1               0               0
             1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
            +---------------+---------------+---------------+---------------+
            |                         time_high                             |
            +---------------+---------------+--------+------+---------------+
            |            time_mid           |   ver  |     time_low         |
            ----+-----------+---------------+--------+------+---------------+
            |var|        clock_seq          |            node               |
            +---+-----------+---------------+---------------+---------------+
            |                            node                               |
            +---------------+---------------+---------------+---------------+
            */

            const time_high = part_a1;
            const time_mid = part_a0;
            const time_low = part_b;
            const time = `${time_high}${time_mid}${time_low}`;
            const clock_seq = part_c2;
            const clockSeq = BigInt(parseInt(clock_seq, 16));
            const node = part_c1 + part_c0;

            // Determine if the node is multicast based on the first bit of 'node'
            const multicastBit = parseInt(node.substring(0, 1), 16) >> 3;  // Extract multicast flag (1 bit) from node
            const multicast = multicastBit === 1;
            const multicastText = multicast ? 'Multicast' : 'Unicast';

            // The reset is based on UUID Variant and the Version of that Variant...
            let nodeType;
            let nodeValue;

            // Multicast or Unicast Addressed node
            nodeType = multicast ? 'MAC Address (Multicast)' : 'MAC Address (Unicast)';
            nodeValue = node.match(/.{2}/g).join(':');

            // The epoch is October 15, 1582 (start of UUID time)
            const epochInMs = BigInt(Date.UTC(1582, 9, 15));

            // Get 'YYYY-MMM-DD HH:MM:SS.mmm.uuu UTC'
            const timestampText = makeTimestamp(time_high, time_mid, time_low, epochInMs, localTime, 6);

            // Return Variant 2 UUIDv1 Decoded
            return {

                UUID: uuid,

                Variant: variant,
                VariantText: variantText,

                Version: version,
                VersionText: versionText,

                Value1Name: "Timestamp",
                Value1: timestampText,

                Value2Name: "Clock Sequence",
                Value2: clockSeq,

                Value3Name: "",
                Value3: "",

                Value4Name: "Node Type",
                Value4: nodeType,

                Value5Name: "Node Address",
                Value5: `${nodeValue}`,

                Value6Name: "",
                Value6: "",

                NumberName: "Random Number",
                NumberText: `0x${time_high}${time_mid}${time_low}`,

                time_low: time_low,
                time_mid: time_mid,
                time_high: time_high,
                time: time,
                clock_seq: clock_seq,
                multicast: multicast,
                multicastText: multicastText,
                node: node,
            };
        }

        // ƒ UUIDv7 - Unix Epoch Timestamp UUID
        function uuidvar2v7()
        {
            /*
             UUIDv7 Field and Bit Layout - Unix Epoch Timestamp UUID:
             3             2               1               0               0
             1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
            +---------------+---------------+---------------+---------------+
            |                         unix_ts1_ms                           |
            +---------------+---------------+--------+------+---------------+
            |            unix_ts0_ms        |   ver  |     rand_a           |
            ----+-----------+---------------+--------+------+---------------+
            |var|        rand_b2            |            rand_b1            |
            +---+-----------+---------------+---------------+---------------+
            |                            rand_b0                            |
            +---------------+---------------+---------------+---------------+
            */

            const unix_ts1_ms = part_a1;
            const unix_ts0_ms = part_a0;
            const unix_ts_ms = `${unix_ts1_ms}${unix_ts0_ms}`;
            const rand_a = part_b;
            const rand_b2 = part_c2;
            const rand_b1 = part_c1;
            const rand_b0 = part_c0;
            const rand_b = `${rand_b2}${rand_b1}${rand_b0}`;
            const rand = `${rand_a}${rand_b}`;

            // The epoch is January 1, 1970 (start of UNIX time)
            const epochInMs = BigInt(Date.UTC(1970, 1, 1));

            // Get 'YYYY-MMM-DD HH:MM:SS.mmm.uuu UTC' - v7 onlt has a High and Low, no Mid
            const timestampText = makeTimestamp(unix_ts1_ms, 0, unix_ts0_ms, epochInMs, localTime, 7);

            // Return Variant 2 UUIDv1 Decoded
            return {

                UUID: uuid,

                Variant: variant,
                VariantText: variantText,

                Version: version,
                VersionText: versionText,

                Value1Name: "Timestamp",
                Value1: timestampText,

                Value2Name: "",
                Value2: "",

                Value3Name: "",
                Value3: "",

                Value4Name: "rand_a",
                Value4: rand_a,

                Value5Name: "rand_b",
                Value5: rand_b,

                Value6Name: "",
                Value6: '',

                NumberName: "Random Number",
                NumberText: `0x${rand}`,

                rand_a: rand_a,
                rand_b: rand_b,
                rand: rand,

                unix_ts_ms: unix_ts_ms,

                Random: rand
            };
        }

        // ƒ UUIDv8 - Custom Encoding Format UUID
        function uuidvar2v8()
        {
            /*
             UUIDv8 Field and Bit Layout - Custom Encoding Format UUID:
             3             2               1               0               0
             1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
            +---------------+---------------+---------------+---------------+
            |                         custom_a1                             |
            +---------------+---------------+--------+------+---------------+
            |            custom_a0          |   ver  |     custom_b         |
            ----+-----------+---------------+--------+------+---------------+
            |var|        custom_c2          |            custom_c1          |
            +---+-----------+---------------+---------------+---------------+
            |                            custom_c0                          |
            +---------------+---------------+---------------+---------------+
            */

            const custom_a1 = part_a1;
            const custom_a0 = part_a0;
            const custom_a = `${custom_a1}${custom_a0}`;
            const custom_b = part_b;
            const custom_c2 = part_c2;
            const custom_c1 = part_c1;
            const custom_c0 = part_c0;
            const custom_c = `${custom_c2}${custom_c1}${custom_c0}`;

            const custom = `${custom_a}${custom_b}${custom_c}`;

            // Return Variant 2 UUIDv1 Decoded
            return {

                UUID: uuid,

                Variant: variant,
                VariantText: variantText,

                Version: version,
                VersionText: versionText,

                Value1Name: "custom_a",
                Value1: custom_a,

                Value2Name: "custom_b",
                Value2: custom_b,

                Value3Name: "custom_c",
                Value3: custom_c,

                Value4Name: "",
                Value4: '',

                Value5Name: "",
                Value5: '',

                Value6Name: "",
                Value6: '',

                NumberName: "Custom Encoding",
                NumberText: `0x${custom}`,

                custom_a: custom_a,
                custom_b: custom_b,
                custom_c: custom_c,

                Custom: custom
            };
        }

        // ƒ UUIDv3, Microsoft GUID, UUIDv1 - 14 - Unused /  reserved UUID variants
        function uuidvar3reserved()
        {
            // decoded by default as a generic UUID

            return uuidGenericLayout();
        }

        /*
         UUID Generic Structure:
         3             2               1               0               0
         1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
        +---------------+---------------+---------------+---------------+
        |                         part_a1                               |
        +---------------+---------------+--------+------+---------------+
        |            part_a0            |   ver  |     part_b           |
        ----+-----------+---------------+--------+------+---------------+
        |var|        part_c2            |            part_c1            |
        +---+-----------+---------------+---------------+---------------+
        |                            part_c0                            |
        +---------------+---------------+---------------+---------------+
        */

        // ƒ uuidGenericLayout - Generic UUID Layout
        function uuidGenericLayout()
        {
            const random = `${part_a1}${part_a0}${part_b}${part_c2}${part_c1}${part_c0}`;

            // Return Generic UUID Decoded
            return {

                UUID: uuid,

                Variant: variant,
                VariantText: variantText,

                Version: version,
                VersionText: versionText,

                Value1Name: "part_a",
                Value1: part_a,

                Value2Name: "part_b",
                Value2: part_b,

                Value3Name: "part_c",
                Value3: part_c,

                Value4Name: "",
                Value4: '',

                Value5Name: "",
                Value5: '',

                Value6Name: "",
                Value6: '',

                NumberName: "Random Number",
                NumberText: `0x${random}`,

                part_a: part_a,
                part_b: part_b,
                part_c: part_c,

                Random: random
            };
        }

        // M A I N - D E C O D E R

        // Split the UUID into parts: aaaaaaaa-aaaa-vbbb-Vccc-cccccccccccc
        //                            11111111 0000       222 111100000000
        if (!uuid)
        {
            // return NIL for a missing UUID
            return {
                UUID: uuid,
                Variant: variant,
                VariantText: "NIL Value",

                Version: version,
                VersionText: "Reserved / NIL",

                Value1Name: "",
                Value1: "",
                Value2Name: "",
                Value2: "",
                Value3Name: "",
                Value3: "",
                Value4Name: "",
                Value4: "",
                Value5Name: "",
                Value5: "",
                Value6Name: "",
                Value6: "",

                NumberName: "",
                NumberText: "",

                NIL: true,
                NILText: "00000000-0000-0000-0000-000000000000"
            };
        }

        // These pieces are common divisions of all UUIDs and they are interpreted
        // based on the UUID variant and version.
        uuid = uuid.toLowerCase();
        const UUID = uuid.toUpperCase();
        const [part_a1, part_a0, ver_part_b, var_part_c1, part_c1_c0] = uuid.split('-');
        const part_a = `${part_a1}${part_a0}`;
        const version = parseInt(ver_part_b.substring(0, 1), 16);
        const part_b = ver_part_b.substring(1);
        const variant = (parseInt(var_part_c1.substring(0, 1), 16) >> 2) & 0b11;
        const part_c2 = (parseInt(var_part_c1.substring(0, 1), 16) & 0b11).toString(16) + var_part_c1.substring(1);
        const part_c1 = part_c1_c0.substring(0, 4);
        const part_c0 = part_c1_c0.substring(4);
        const part_c = `${part_c2}${part_c1}${part_c0}`;

        // How to interpret the UUID...
        const variantText = UUID_VARIANTS[variant];
        let versionText = '<undetermined>';
        let variantValue1Name = 'part_a1';
        let variantValue1 = part_a1;
        let variantValue2Name = 'part_a0';
        let variantValue2 = part_a0;
        let variantValue3Name = 'part_b';
        let variantValue3 = part_b;
        let variantValue4Name = 'part_c2';
        let variantValue4 = part_c2;
        let variantValue5Name = 'part_c1';
        let variantValue5 = part_c1;
        let variantValue6Name = 'part_c0';
        let variantValue6 = part_c0;

        // If every thing is "0" then it's a NIL Value
        if (UUID === "00000000-0000-0000-0000-000000000000")
        {
            return {
                UUID: uuid,
                Variant: variant,
                VariantText: "NIL Value",

                Version: version,
                VersionText: "Reserved / NIL",

                Value1Name: "",
                Value1: "",
                Value2Name: "",
                Value2: "",
                Value3Name: "",
                Value3: "",
                Value4Name: "",
                Value4: "",
                Value5Name: "",
                Value5: "",
                Value6Name: "",
                Value6: "",

                NumberName: "",
                NumberText: "",

                NIL: true,
                NILText: "00000000-0000-0000-0000-000000000000"
            };
        }
        else if (UUID === "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF")
        {
            return {
                UUID: uuid,
                Variant: variant,
                VariantText: "MAX Value",

                Version: version,
                VersionText: "Reserved / MAX",

                Value1Name: "",
                Value1: "",
                Value2Name: "",
                Value2: "",
                Value3Name: "",
                Value3: "",
                Value4Name: "",
                Value4: "",
                Value5Name: "",
                Value5: "",
                Value6Name: "",
                Value6: "",

                NumberName: "",
                NumberText: "",

                MAX: true,
                MAXText: "FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF"
            };
        }
        else
        {
            // Decode the UUID based on the variant and version
            return uuidVariants[variant]();
        }
    },

    /**
     * @func toSnakeCase
     * @memberof mcode
     * @desc Returns a lowercase-snake-case-name by converting a string's spaces to hyphens and discarding non-alphanumeric characters.
     * @param {string} str the string to convert to snake case.
     * @returns {string} a value representing the snake case version of the string.
     */
    toSnakeCase: function (str)
    {
        return str
            .toLowerCase()            // convert the entire string to lowercase
            .replace(/[^\w\s]/g, '')  // remove any non-alphanumeric characters except spaces
            .replace(/\s+/g, '-')     // replace spaces with hyphens
            .replace(/^-+|-+$/g, ''); // remove any leading or trailing hyphens
    },

    /**
     * @func fromSnakeCase
     * @memberof mcode
     * @desc Returns a text string by converting a snake-case-name to Title Case Name sentence.
     * @param {string} str the string to convert from snake case.
     * @returns {string} a value representing the Title Case version of the string.
     */
    fromSnakeCase: function (str)
    {
        return str
            .split('-')               // split the string at hyphens
            .map(word => word.charAt(0).toUpperCase() + word.slice(1)) // capitalize the first letter of each word
            .join(' ');               // join the words with spaces
    },

    /**
     * @function sleep
     * @memberof mcode
     * @desc Pauses execution for a specified duration.
     * @param {number} ms The duration to sleep in milliseconds.
     * @returns {Promise} A promise that resolves after the specified duration.
     */
    sleep: function (ms)
    {
        return new Promise(resolve => setTimeout(resolve, ms));
    },

    /**
     * @function generateRandomId
     * @memberof mcode
     * @desc Generates a random identifier in hexadecimal format, useful for creating unique IDs in the UI.
     * The number generated is a random 6-digit hexadecimal string (e.g., '3F5A9C') which can be used as a suffix or part of an identifier.
     * This number will be in the range of 000000 to FFFFFF (0 to 16,777,215 in decimal).
     * @param {string} prefix A prefix to prepend to the time for a complete identifier.
     * @returns {string} A unique random identifier, optionally prefixed for better scope control and identifcation.
     */
    generateRandomId: function (prefix)
    {
        // Generate a random 6-digit hexadecimal string
        const id = Math.floor(Math.random() * 0x1000000).toString(16).padStart(6, '0').toUpperCase();
        return prefix ? `${prefix}-${id}` : id;
    },

    /**
     * @function encodeJson
     * @memberof mcode
     * @desc Encodes a value as a JSON string with special character replacements.
     * @param {any} value The value to encode.
     * @returns {string} The encoded JSON string.
     */
    encodeJson: function (value)
    {
        if (value === undefined || value === null) return '';

        // Use JSON.stringify, then escape critical HTML-breaking and XSS (Cross Site Scripting) characters
        return JSON.stringify(value)
            .replace(/</g, '\\u003C')
            .replace(/>/g, '\\u003E')
            .replace(/&/g, '\\u0026')
            .replace(/'/g, '\\u0027')
            .replace(/"/g, '\\u0022');
    },

    /**
     * @function encodeAttr
     * @memberof backend.uic.grafx
     * @desc Encodes special HTML characters in a string for safe inclusion in HTML attributes.
     * @param {string} value - The value to escape
     * @returns {string} The escaped value
     */
    encodeAttr: function (value)
    {
        if (value === undefined || value === null) return '';

        return String(value)
            .replace(/&/g, '&amp;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');
    },

    /**
     * @function classExport
     * @memberof mcode
     * @desc >
     * Safely registers a class in the global namespace or a specified namespace if it is not already defined.
     * If Namespace.ClassName already exists and has bootstrapPending(), it is called, and the existing value is returned.
     * See GitHub Repo 'MicroCODEIncorporated/TemplateJS' for a Class Template designed for this invocation.
     * When this is used as a module wrapper, it becomes an Immediately Invoked Function Expression (IIFE) invoked on 'this' which
     * represents the global object (window in a browser, global in Node.js).
     * That IIFE returns the 'Class' object to be assigned to the global object.
     * The Universal Module Definition (UMD) pattern supports Asynchronous Module Definition (AMD),
     * CommonJS / Node.js, and Browser 'global' usage. {0008}
     * @param {string|null} namespaceName - [Optional] global namespace (e.g., "MyApp"), if you want
     * your Class available directly on the Global/Root namespace pass an empty string "".
     * @param {string} className - Name of the class to export.
     * @param {Function} factory - A function (root: any) that returns the class constructor.
     * @returns {Function|any} The class constructor or the existing class if it already exists.
     * @example
     *
     *    mcode.classExport('Namespace', 'ClassName', function (root)
     *    {
     *        class ClassName...  // the entire class is declared within 'function (root) { * }'.
     *    });
     *
     */
    classExport: function (namespaceName, className, factory)
    {
        if (typeof className !== 'string' || !className.trim()) throw new Error('mcode.classExport() requires a Class Name.');
        if (typeof factory !== 'function') throw new Error('mcode.classExport() requires a function to define the Class.');

        const root = (typeof globalThis !== 'undefined')
            ? globalThis
            : (typeof self !== 'undefined' ? self : this);

        const namespace = namespaceName
            ? (root[namespaceName] = root[namespaceName] || {})
            : root;

        if (!namespace[className])
        {
            namespace[className] = factory(root);
        }
        else if (typeof namespace[className].bootstrapPending === 'function')
        {
            namespace[className].bootstrapPending();
        }

        return namespace[className];
    }
};

// #endregion

// #region  M E T H O D - E X P O R T S

// Immediately Invoked Function Expression (IIFE) invoked on 'this' which
// represents the global object (window in a browser, global in Node.js).
// This IIFE returns the 'mcode' object to be assigned to the global object.
// The Universal Module Definition (UMD) pattern supports Asynchronous Module Definition (AMD),
// CommonJS / Node.js, and Browser 'global' usage. {0008}
(
    /**
     * @function (IIFE)
     * @desc Universal Module Definition (UMD) to support AMD, CommonJS/Node.js, and browser global
     * @param {any} root the global object (window, self, global, etc.) being updated.
     * @param {any} factory a function that returns the exports of the module. This function is invoked in
     * the context of the global object when the module is loaded. The return value of this function is used
     * as the exported value of the module when it's not being used with AMD or Node.js module systems.
     * This function is where you define what your module exports.
     */
    function (root, factory)
    {
        if (typeof define === 'function' && define.amd)
        {
            // AMD. Register as an anonymous module.
            define([], factory);
        }
        else if (typeof module === 'object' && module.exports)
        {
            // Node. Does not work with strict CommonJS, but
            // only CommonJS-like environments that support module.exports, like Node.
            module.exports = factory();
        }
        else
        {
            // Browser globals (root is 'window')
            root.mcode = factory();
        }

    }(  // root: the global object (window, self, global, etc.)
        (typeof self !== 'undefined') ? self : this,

        // factory: a function that returns the exports of the module
        function () {return mcode;})
);

// #endregion

// #endregion
// #endregion