var CABLES;
/******/ (() => { // webpackBootstrap
/******/ 	"use strict";
/******/ 	// The require scope
/******/ 	var __webpack_require__ = {};
/******/ 	
/************************************************************************/
/******/ 	/* webpack/runtime/define property getters */
/******/ 	(() => {
/******/ 		// define getter functions for harmony exports
/******/ 		__webpack_require__.d = (exports, definition) => {
/******/ 			for(var key in definition) {
/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ 				}
/******/ 			}
/******/ 		};
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
/******/ 	(() => {
/******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ 	})();
/******/ 	
/******/ 	/* webpack/runtime/make namespace object */
/******/ 	(() => {
/******/ 		// define __esModule on exports
/******/ 		__webpack_require__.r = (exports) => {
/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 			}
/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
/******/ 		};
/******/ 	})();
/******/ 	
/************************************************************************/
var __webpack_exports__ = {};

// EXPORTS
__webpack_require__.d(__webpack_exports__, {
  "default": () => (/* binding */ core)
});

// NAMESPACE OBJECT: ./src/core/utils.js
var utils_namespaceObject = {};
__webpack_require__.r(utils_namespaceObject);
__webpack_require__.d(utils_namespaceObject, {
  UTILS: () => (UTILS),
  ajax: () => (ajax),
  ajaxSync: () => (ajaxSync),
  basename: () => (basename),
  cacheBust: () => (cacheBust),
  clamp: () => (clamp),
  cleanJson: () => (cleanJson),
  copyArray: () => (copyArray),
  filename: () => (filename),
  generateUUID: () => (generateUUID),
  getShortOpName: () => (getShortOpName),
  keyCodeToName: () => (keyCodeToName),
  logErrorConsole: () => (logErrorConsole),
  logStack: () => (logStack),
  map: () => (map),
  prefixedHash: () => (prefixedHash),
  request: () => (request),
  shortId: () => (shortId),
  shuffleArray: () => (shuffleArray),
  simpleId: () => (simpleId),
  smoothStep: () => (smoothStep),
  smootherStep: () => (smootherStep),
  uuid: () => (uuid)
});

// NAMESPACE OBJECT: ./src/core/anim.js
var anim_namespaceObject = {};
__webpack_require__.r(anim_namespaceObject);
__webpack_require__.d(anim_namespaceObject, {
  ANIM: () => (ANIM),
  Anim: () => (Anim)
});

;// CONCATENATED MODULE: ./src/core/constants.js
const CONSTANTS = {
    "ANIM": {
        "EASINGS": [
            "linear",
            "absolute",
            "smoothstep",
            "smootherstep",
            "Cubic In",
            "Cubic Out",
            "Cubic In Out",
            "Expo In",
            "Expo Out",
            "Expo In Out",
            "Sin In",
            "Sin Out",
            "Sin In Out",
            "Quart In",
            "Quart Out",
            "Quart In Out",
            "Quint In",
            "Quint Out",
            "Quint In Out",
            "Back In",
            "Back Out",
            "Back In Out",
            "Elastic In",
            "Elastic Out",
            "Bounce In",
            "Bounce Out",
        ],
        "EASING_LINEAR": 0,
        "EASING_ABSOLUTE": 1,
        "EASING_SMOOTHSTEP": 2,
        "EASING_SMOOTHERSTEP": 3,
        "EASING_CUBICSPLINE": 4,

        "EASING_CUBIC_IN": 5,
        "EASING_CUBIC_OUT": 6,
        "EASING_CUBIC_INOUT": 7,

        "EASING_EXPO_IN": 8,
        "EASING_EXPO_OUT": 9,
        "EASING_EXPO_INOUT": 10,

        "EASING_SIN_IN": 11,
        "EASING_SIN_OUT": 12,
        "EASING_SIN_INOUT": 13,

        "EASING_BACK_IN": 14,
        "EASING_BACK_OUT": 15,
        "EASING_BACK_INOUT": 16,

        "EASING_ELASTIC_IN": 17,
        "EASING_ELASTIC_OUT": 18,

        "EASING_BOUNCE_IN": 19,
        "EASING_BOUNCE_OUT": 21,

        "EASING_QUART_IN": 22,
        "EASING_QUART_OUT": 23,
        "EASING_QUART_INOUT": 24,

        "EASING_QUINT_IN": 25,
        "EASING_QUINT_OUT": 26,
        "EASING_QUINT_INOUT": 27,
    },

    "OP": {
        "OP_PORT_TYPE_VALUE": 0,
        "OP_PORT_TYPE_NUMBER": 0,
        "OP_PORT_TYPE_FUNCTION": 1,
        "OP_PORT_TYPE_TRIGGER": 1,
        "OP_PORT_TYPE_OBJECT": 2,
        "OP_PORT_TYPE_TEXTURE": 2,
        "OP_PORT_TYPE_ARRAY": 3,
        "OP_PORT_TYPE_DYNAMIC": 4,
        "OP_PORT_TYPE_STRING": 5,

        "OP_VERSION_PREFIX": "_v",
    },

    "PORT": {
        "PORT_DIR_IN": 0,
        "PORT_DIR_OUT": 1,
    },

    "PACO": {
        "PACO_CLEAR": 0,
        "PACO_VALUECHANGE": 1,
        "PACO_OP_DELETE": 2,
        "PACO_UNLINK": 3,
        "PACO_LINK": 4,
        "PACO_LOAD": 5,
        "PACO_OP_CREATE": 6,
        "PACO_OP_ENABLE": 7,
        "PACO_OP_DISABLE": 8,
        "PACO_UIATTRIBS": 9,
        "PACO_VARIABLES": 10,
        "PACO_TRIGGERS": 11,
        "PACO_PORT_SETVARIABLE": 12,
        "PACO_PORT_SETANIMATED": 13,
        "PACO_PORT_ANIM_UPDATED": 14,
        "PACO_DESERIALIZE": 15,
        "PACO_OP_RELOAD": 16
    },
};

;// CONCATENATED MODULE: ./src/core/utils.js

/**
 * @namespace external:CABLES#Utils
 */



const UTILS = {};
/**
 * Merge two Float32Arrays.
 * @function float32Concat
 * @memberof Utils
 * @param {Float32Array} first Left-hand side array
 * @param {Float32Array} second Right-hand side array
 * @return {Float32Array}
 * @static
 */
UTILS.float32Concat = function (first, second)
{
    if (!(first instanceof Float32Array)) first = new Float32Array(first);
    if (!(second instanceof Float32Array)) second = new Float32Array(second);

    const result = new Float32Array(first.length + second.length);

    result.set(first);
    result.set(second, first.length);

    return result;
};

/**
 * get op shortname: only last part of fullname and without version
 * @function getShortOpName
 * @memberof CABLES
 * @param {string} fullname full op name
 * @static
 */
const getShortOpName = function (fullname)
{
    let name = fullname.split(".")[fullname.split(".").length - 1];

    if (name.contains(CONSTANTS.OP.OP_VERSION_PREFIX))
    {
        const n = name.split(CONSTANTS.OP.OP_VERSION_PREFIX)[1];
        name = name.substring(0, name.length - (CONSTANTS.OP.OP_VERSION_PREFIX + n).length);
    }
    return name;
};

/**
 * randomize order of an array
 * @function shuffleArray
 * @memberof Utils
 * @param {Array|Float32Array} array {Array} original
 * @return {Array|Float32Array} shuffled array
 * @static
 */
const shuffleArray = function (array)
{
    for (let i = array.length - 1; i > 0; i--)
    {
        const j = Math.floor(Math.seededRandom() * (i + 1));
        const temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    return array;
};


/**
 * generate a short "relativly unique" id
 * @function shortId
 * @memberof Utils
 * @return {String} generated ID
 * @static
 */

const _shortIds = {};
const _shortId = function ()
{
    let str = Math.random().toString(36).substr(2, 9);

    if (_shortIds.hasOwnProperty(str)) str = _shortId();
    _shortIds[str] = true;
    return str;
};
const shortId = _shortId;


/**
 * generate a UUID
 * @function uuid
 * @memberof Utils
 * @return {String} generated UUID
 * @static
 */
const _uuid = function ()
{
    let d = new Date().getTime();
    const uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) =>
    {
        const r = (d + Math.random() * 16) % 16 | 0;
        d = Math.floor(d / 16);
        return (c == "x" ? r : (r & 0x3) | 0x8).toString(16);
    });
    return uuid;
};
const uuid = _uuid;
const generateUUID = _uuid;



function cleanJson(obj)
{
    for (const i in obj)
    {
        if (obj[i] && typeof objValue === "object" && obj[i].constructor === Object) obj[i] = cleanJson(obj[i]);

        if (obj[i] === null || obj[i] === undefined) delete obj[i];
        else if (Array.isArray(obj[i]) && obj[i].length == 0) delete obj[i];
    }

    return obj;
}


/**
 * @see http://stackoverflow.com/q/7616461/940217
 * @memberof Utils
 * @param str
 * @param prefix
 * @return {string}
 */
const _prefixedHash = function (str, prefix = "id")
{
    let hash = 0;
    if (Array.prototype.reduce)
    {
        hash = str.split("").reduce((a, b) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a; }, 0);
    }
    else
    {
        if (str.length > 0)
        {
            for (let i = 0; i < str.length; i++)
            {
                let character = str.charCodeAt(i);
                hash = ((hash << 5) - hash) + character;
                hash &= hash; // Convert to 32bit integer
            }
        }
    }
    return prefix + "" + hash;
};
const prefixedHash = _prefixedHash;

/**
 * generate a simple ID
 * @function simpleId
 * @memberof Utils
 * @return {Number} new id
 * @static
 */
let simpleIdCounter = 0;
const simpleId = function ()
{
    simpleIdCounter++;
    return simpleIdCounter;
};

/**
 * smoothStep a value
 * @function smoothStep
 * @memberof Utils
 * @function
 * @param {Number} perc value value to be smoothed [0-1]
 * @return {Number} smoothed value
 * @static
 */
const smoothStep = function (perc)
{
    const x = Math.max(0, Math.min(1, (perc - 0) / (1 - 0)));
    perc = x * x * (3 - 2 * x); // smoothstep
    return perc;
};

/**
 * smootherstep a value
 * @function smootherStep
 * @memberof Utils
 * @param {Number} perc value to be smoothed [0-1]
 * @return {Number} smoothed value
 * @static
 */
const smootherStep = function (perc)
{
    const x = Math.max(0, Math.min(1, (perc - 0) / (1 - 0)));
    perc = x * x * x * (x * (x * 6 - 15) + 10); // smootherstep
    return perc;
};


/**
 * clamp number / make sure its between min/max
 * @function clamp
 * @memberof Utils
 * @param {Number} value value to be mapped
 * @param {Number} min minimum value
 * @param {Number} max maximum value
 * @static
 */
const clamp = function (value, min, max)
{
    return Math.min(Math.max(value, min), max);
};

/**
 * map a value in a range to a value in another range
 * @function map
 * @memberof Utils
 * @param {Number} x value to be mapped
 * @param {Number} _oldMin old range minimum value
 * @param {Number} _oldMax old range maximum value
 * @param {Number} _newMin new range minimum value
 * @param {Number} _newMax new range maximum value
 * @param {Number} _easing
 * @return {Number} mapped value
 * @static
 */
const map = function (x, _oldMin, _oldMax, _newMin, _newMax, _easing)
{
    if (x >= _oldMax) return _newMax;
    if (x <= _oldMin) return _newMin;

    let reverseInput = false;
    const oldMin = Math.min(_oldMin, _oldMax);
    const oldMax = Math.max(_oldMin, _oldMax);
    if (oldMin != _oldMin) reverseInput = true;

    let reverseOutput = false;
    const newMin = Math.min(_newMin, _newMax);
    const newMax = Math.max(_newMin, _newMax);
    if (newMin != _newMin) reverseOutput = true;

    let portion = 0;
    let r = 0;

    if (reverseInput) portion = ((oldMax - x) * (newMax - newMin)) / (oldMax - oldMin);
    else portion = ((x - oldMin) * (newMax - newMin)) / (oldMax - oldMin);

    if (reverseOutput) r = newMax - portion;
    else r = portion + newMin;

    if (!_easing) return r;
    if (_easing == 1)
    {
        // smoothstep
        x = Math.max(0, Math.min(1, (r - _newMin) / (_newMax - _newMin)));
        return _newMin + x * x * (3 - 2 * x) * (_newMax - _newMin);
    }
    if (_easing == 2)
    {
        // smootherstep
        x = Math.max(0, Math.min(1, (r - _newMin) / (_newMax - _newMin)));
        return _newMin + x * x * x * (x * (x * 6 - 15) + 10) * (_newMax - _newMin);
    }

    return r;
};

/**
 * @namespace Math
 */
/**
 * set random seed for seededRandom()
 * @memberof Math
 * @type Number
 * @static
 */
Math.randomSeed = 1;


Math.setRandomSeed = function (seed)
{
    // https://github.com/cables-gl/cables_docs/issues/622
    Math.randomSeed = seed * 50728129;
    if (seed != 0)
    {
        Math.randomSeed = Math.seededRandom() * 17624813;
        Math.randomSeed = Math.seededRandom() * 9737333;
    }
};


/**
 * generate a seeded random number
 * @function seededRandom
 * @memberof Math
 * @param {Number} max minimum possible random number
 * @param {Number} min maximum possible random number
 * @return {Number} random value
 * @static
 */
Math.seededRandom = function (max, min)
{
    if (Math.randomSeed === 0) Math.randomSeed = Math.random() * 999;
    max = max || 1;
    min = min || 0;

    Math.randomSeed = (Math.randomSeed * 9301 + 49297) % 233280;
    const rnd = Math.randomSeed / 233280.0;

    return min + rnd * (max - min);
};


// ----------------------------------------------------------------

/**
 * returns true if parameter is a number
 * @function isNumeric
 * @memberof Utils
 * @param {Any} n value The value to check.
 * @return {Boolean}
 * @static
 */
UTILS.isNumeric = function (n)
{
    return !isNaN(parseFloat(n)) && isFinite(n);
};

/**
 * returns true if parameter is array
 * @function isArray
 * @param {Any} v value Value to check
 * @memberof Utils
 * @return {Boolean}
 * @static
 */
UTILS.isArray = function (v)
{
    return Object.prototype.toString.call(v) === "[object Array]";
};

/**
 * @namespace String
 */

/**
 * append a linebreak to a string
 * @function endl
 * @memberof String
 * @return {String} string with newline break appended ('\n')
 */
String.prototype.endl = function ()
{
    return this + "\n";
};

/**
 * return true if string starts with prefix
 * @function startsWith
 * @memberof String
 * @param {String} prefix The prefix to check.
 * @return {Boolean}
 */
String.prototype.startsWith = function (prefix)
{
    if (!this || !prefix) return false;
    if (this.length >= prefix.length)
    {
        if (this.substring(0, prefix.length) == prefix) return true;
    }
    return false;
    // return this.indexOf(prefix) === 0;
};

/**
 * return true if string ends with suffix
 * @function endsWith
 * @memberof String
 * @param {String} suffix
 * @return {Boolean}
 */
String.prototype.endsWith = String.prototype.endsWith || function (suffix)
{
    return this.match(suffix + "$") == suffix;
};

/**
 * return true if string contains string
 * @function contains
 * @memberof String
 * @param {String} searchStr
 * @return {Boolean}
 */
String.prototype.contains = String.prototype.contains || function (searchStr)
{
    return this.indexOf(searchStr) > -1;
};



// ----------------------------------------------------------------

/**
 * append a unique/random parameter to a url, so the browser is forced to reload the file, even if its cached
 * @function cacheBust
 * @static
 * @memberof Utils
 * @param {String} url The url to append the cachebuster parameter to.
 * @return {String} url with cachebuster parameter
 */
const cacheBust = function (url = "")
{
    if (!url) return "";
    if (url.startsWith("data:")) return;
    if (url.contains("?")) url += "&";
    else url += "?";
    return url + "cache=" + CABLES.uuid();
};

/**
 * copy the content of an array
 * @function copyArray
 * @static
 * @memberof Utils
 * @param {Array} src sourceArray
 * @param {Array} dst optional
 * @return {Array} dst
 */
const copyArray = function (src, dst)
{
    if (!src) return null;
    dst = dst || [];
    dst.length = src.length;
    for (let i = 0; i < src.length; i++)
    {
        dst[i] = src[i];
    }

    return dst;
};


/**
 * return the filename part of a url without extension
 * @function basename
 * @static
 * @memberof Utils
 * @param {String} url
 * @return {String} just the filename
 */
const basename = function (url)
{
    let name = CABLES.filename(url);

    const parts2 = name.split(".");
    name = parts2[0];

    return name;
};

/**
 * output a stacktrace to the console
 * @function logStack
 * @static
 * @memberof Utils
 */
const logStack = function ()
{
    console.log("logstack", (new Error()).stack);
};

/**
 * return the filename part of a url
 * @function filename
 * @static
 * @memberof Utils
 * @param {String} url
 * @return {String} just the filename
 */
const filename = function (url)
{
    let name = "";
    if (!url) return "";

    if (url.startsWith("data:") && url.contains(":"))
    {
        const parts = url.split(",");
        return parts[0];
    }

    let parts = (url + "").split("/");
    if (parts.length > 0)
    {
        const str = parts[parts.length - 1];
        let parts2 = str.split("?");
        name = parts2[0];
    }

    return name || "";
};


const ajaxSync = function (url, cb, method, post, contenttype)
{
    request({
        "url": url,
        "cb": cb,
        "method": method,
        "data": post,
        "contenttype": contenttype,
        "sync": true,
    });
};

/**
 * make an ajax request
 * @static
 * @function ajax
 * @param url
 * @param cb
 * @param method
 * @param post
 * @param contenttype
 * @param jsonP
 * @param headers
 * @param options
 */
const ajax = function (url, cb, method, post, contenttype, jsonP, headers = {}, options = {})
{
    const requestOptions = {
        "url": url,
        "cb": cb,
        "method": method,
        "data": post,
        "contenttype": contenttype,
        "sync": false,
        "jsonP": jsonP,
        "headers": headers,
    };
    if (options && options.credentials) requestOptions.credentials = options.credentials;
    request(requestOptions);
};

const request = function (options)
{
    if (!options.hasOwnProperty("asynch")) options.asynch = true;

    let xhr;
    try
    {
        xhr = new XMLHttpRequest();
    }
    catch (e) {}

    xhr.onreadystatechange = function ()
    {
        if (xhr.readyState != 4) return;

        if (options.cb)
        {
            if (xhr.status == 200 || xhr.status == 0) options.cb(false, xhr.responseText, xhr);
            else options.cb(true, xhr.responseText, xhr);
        }
    };

    try
    {
        xhr.open(options.method ? options.method.toUpperCase() : "GET", options.url, !options.sync);
    }
    catch (e)
    {
        if (options.cb && e) options.cb(true, e.msg, xhr);
    }

    if (typeof options.headers === "object")
    {
        if (options.headers)
        {
            const keys = Object.keys(options.headers);
            for (let i = 0; i < keys.length; i++)
            {
                const name = keys[i];
                const value = options.headers[name];
                xhr.setRequestHeader(name, value);
            }
        }
    }

    if (options.credentials && options.credentials !== "omit")
    {
        xhr.withCredentials = true;
    }

    try
    {
        if (!options.post && !options.data)
        {
            xhr.send();
        }
        else
        {
            xhr.setRequestHeader(
                "Content-type",
                options.contenttype ? options.contenttype : "application/x-www-form-urlencoded",
            );
            xhr.send(options.data || options.post);
        }
    }
    catch (e)
    {
        if (options.cb) options.cb(true, e.msg, xhr);
    }
};


const keyCodeToName = function (keyCode)
{
    if (!keyCode && keyCode !== 0) return "Unidentified";
    const keys = {
        "8": "Backspace",
        "9": "Tab",
        "12": "Clear",
        "13": "Enter",
        "16": "Shift",
        "17": "Control",
        "18": "Alt",
        "19": "Pause",
        "20": "CapsLock",
        "27": "Escape",
        "32": "Space",
        "33": "PageUp",
        "34": "PageDown",
        "35": "End",
        "36": "Home",
        "37": "ArrowLeft",
        "38": "ArrowUp",
        "39": "ArrowRight",
        "40": "ArrowDown",
        "45": "Insert",
        "46": "Delete",
        "112": "F1",
        "113": "F2",
        "114": "F3",
        "115": "F4",
        "116": "F5",
        "117": "F6",
        "118": "F7",
        "119": "F8",
        "120": "F9",
        "121": "F10",
        "122": "F11",
        "123": "F12",
        "144": "NumLock",
        "145": "ScrollLock",
        "224": "Meta"
    };
    if (keys[keyCode])
    {
        return keys[keyCode];
    }
    else
    {
        return String.fromCharCode(keyCode);
    }
};
// ----------------------------------------------------------------

window.performance = window.performance || {
    "offset": Date.now(),
    "now": function now()
    {
        return Date.now() - this.offset;
    },
};


const logErrorConsole = function (initiator)
{
    CABLES.errorConsole = CABLES.errorConsole || { "log": [] };
    CABLES.errorConsole.log.push({ "initiator": initiator, "arguments": arguments });

    if (!CABLES.errorConsole.ele)
    {
        const ele = document.createElement("div");
        ele.id = "cablesErrorConsole";
        ele.style.width = "90%";
        ele.style.height = "300px";
        ele.style.zIndex = "9999999";
        ele.style.display = "inline-block";
        ele.style.position = "absolute";
        ele.style.padding = "10px";
        ele.style.fontFamily = "monospace";
        ele.style.color = "red";
        ele.style.backgroundColor = "#200";

        CABLES.errorConsole.ele = ele;
        document.body.appendChild(ele);
    }

    let logHtml = "ERROR<br/>for more info, open your browsers dev tools console (Ctrl+Shift+I or Command+Alt+I)<br/>";

    for (let l = 0; l < CABLES.errorConsole.log.length; l++)
    {
        logHtml += CABLES.errorConsole.log[l].initiator + " ";
        for (let i = 1; i < CABLES.errorConsole.log[l].arguments.length; i++)
        {
            if (i > 2)logHtml += ", ";
            let arg = CABLES.errorConsole.log[l].arguments[i];
            if (arg.constructor.name.indexOf("Error") > -1 || arg.constructor.name.indexOf("error") > -1)
            {
                let txt = "Uncaught ErrorEvent ";
                if (arg.message)txt += " message: " + arg.message;
                logHtml += txt;
            }
            else if (typeof arg == "string")
                logHtml += arg;
            else if (typeof arg == "number")
                logHtml += String(arg) + " ";
        }
        logHtml += "<br/>";
    }


    CABLES.errorConsole.ele.innerHTML = logHtml;
};




;// CONCATENATED MODULE: ../shared/client/src/logger.js
/* eslint-disable no-console */

class Logger
{
    constructor(initiator, options)
    {
        this.initiator = initiator;
        this._options = options;
    }

    stack(t)
    {
        console.info("[" + this.initiator + "] ", t);
        console.log((new Error()).stack);
    }

    groupCollapsed(t)
    {
        if ((CABLES.UI && CABLES.UI.logFilter.filterLog({ "initiator": this.initiator, "level": 0 }, ...arguments)) || !CABLES.logSilent) console.log("[" + this.initiator + "]", ...arguments);

        console.groupCollapsed("[" + this.initiator + "] " + t);
    }

    table(t)
    {
        console.table(t);
    }

    groupEnd()
    {
        console.groupEnd();
    }

    error()
    {
        if ((CABLES.UI && CABLES.UI.logFilter.filterLog({ "initiator": this.initiator, "level": 2 }, ...arguments)) || !CABLES.UI)
        {
            console.error("[" + this.initiator + "]", ...arguments);
        }

        if (this._options && this._options.onError)
        {
            this._options.onError(this.initiator, ...arguments);
            // console.log("emitevent onerror...");
            // CABLES.patch.emitEvent("onError", this.initiator, ...arguments);
            // CABLES.logErrorConsole("[" + this.initiator + "]", ...arguments);
        }
    }

    errorGui()
    {
        if (CABLES.UI) CABLES.UI.logFilter.filterLog({ "initiator": this.initiator, "level": 2 }, ...arguments);
    }

    warn()
    {
        if ((CABLES.UI && CABLES.UI.logFilter.filterLog({ "initiator": this.initiator, "level": 1 }, ...arguments)) || !CABLES.logSilent)
            console.warn("[" + this.initiator + "]", ...arguments);
    }

    verbose()
    {
        if ((CABLES.UI && CABLES.UI.logFilter.filterLog({ "initiator": this.initiator, "level": 0 }, ...arguments)) || !CABLES.logSilent)
            console.log("[" + this.initiator + "]", ...arguments);
    }

    info()
    {
        if ((CABLES.UI && CABLES.UI.logFilter.filterLog({ "initiator": this.initiator, "level": 0 }, ...arguments)) || !CABLES.logSilent)
            console.info("[" + this.initiator + "]", ...arguments);
    }

    log()
    {
        if ((CABLES.UI && CABLES.UI.logFilter.filterLog({ "initiator": this.initiator, "level": 0 }, ...arguments)) || !CABLES.logSilent)
            console.log("[" + this.initiator + "]", ...arguments);
    }

    logGui()
    {
        if (CABLES.UI) CABLES.UI.logFilter.filterLog({ "initiator": this.initiator, "level": 0 }, ...arguments);
    }

    userInteraction(text)
    {
        // this.log({ "initiator": "userinteraction", "text": text });
    }
}

;// CONCATENATED MODULE: ./src/core/anim_key.js


const Key = function (obj)
{
    this.time = 0.0;
    this.value = 0.0;
    // this.ui = null;
    this.onChange = null;
    this._easing = 0;
    // this.bezTangIn = 0;
    // this.bezTangOut = 0;
    // this.bezTime = 0.5;
    // this.bezValue = 0;
    // this.bezTimeIn = -0.5;
    // this.bezValueIn = 0;

    this.cb = null;
    this.cbTriggered = false;

    // const bezierAnim = null;
    // this._updateBezier = false;

    this.setEasing(CONSTANTS.ANIM.EASING_LINEAR);
    this.set(obj);
};

Key.cubicSpline = function (perc, key1, key2)
{
    let
        previousPoint = key1.value,
        previousTangent = key1.bezTangOut,
        nextPoint = key2.value,
        nextTangent = key2.bezTangIn;
    let t = perc;
    let t2 = t * t;
    let t3 = t2 * t;

    return (2 * t3 - 3 * t2 + 1) * previousPoint + (t3 - 2 * t2 + t) * previousTangent + (-2 * t3 + 3 * t2) * nextPoint + (t3 - t2) * nextTangent;
};

Key.easeCubicSpline = function (perc, key2)
{
    return Key.cubicSpline(perc, this, key2);
};


Key.linear = function (perc, key1, key2)
{
    return parseFloat(key1.value) + parseFloat(key2.value - key1.value) * perc;
};

Key.easeLinear = function (perc, key2)
{
    return Key.linear(perc, this, key2);
};

Key.easeAbsolute = function (perc, key2)
{
    return this.value;
};

const easeExpoIn = function (t)
{
    return (t = 2 ** (10 * (t - 1)));
};

Key.easeExpoIn = function (t, key2)
{
    t = easeExpoIn(t);
    return Key.linear(t, this, key2);
};

const easeExpoOut = function (t)
{
    t = -(2 ** (-10 * t)) + 1;
    return t;
};

Key.easeExpoOut = function (t, key2)
{
    t = easeExpoOut(t);
    return Key.linear(t, this, key2);
};

const easeExpoInOut = function (t)
{
    t *= 2;
    if (t < 1)
    {
        t = 0.5 * 2 ** (10 * (t - 1));
    }
    else
    {
        t--;
        t = 0.5 * (-(2 ** (-10 * t)) + 2);
    }
    return t;
};

Key.easeExpoInOut = function (t, key2)
{
    t = easeExpoInOut(t);
    return Key.linear(t, this, key2);
};

Key.easeSinIn = function (t, key2)
{
    t = -1 * Math.cos((t * Math.PI) / 2) + 1;
    return Key.linear(t, this, key2);
};

Key.easeSinOut = function (t, key2)
{
    t = Math.sin((t * Math.PI) / 2);
    return Key.linear(t, this, key2);
};

Key.easeSinInOut = function (t, key2)
{
    t = -0.5 * (Math.cos(Math.PI * t) - 1.0);
    return Key.linear(t, this, key2);
};

const easeCubicIn = function (t)
{
    t = t * t * t;
    return t;
};

Key.easeCubicIn = function (t, key2)
{
    t = easeCubicIn(t);
    return Key.linear(t, this, key2);
};


// b 0
// c 1/2 or 1
// d always 1
// easeOutCubic: function (x, t, b, c, d) {
//     return c*((t=t/d-1)*t*t + 1) + b;

Key.easeInQuint = function (t, key2)
{
    t = t * t * t * t * t;
    return Key.linear(t, this, key2);
};
Key.easeOutQuint = function (t, key2)
{
    t = (t -= 1) * t * t * t * t + 1;
    return Key.linear(t, this, key2);
};
Key.easeInOutQuint = function (t, key2)
{
    if ((t /= 0.5) < 1) t = 0.5 * t * t * t * t * t;
    else t = 0.5 * ((t -= 2) * t * t * t * t + 2);
    return Key.linear(t, this, key2);
};

Key.easeInQuart = function (t, key2)
{
    t = t * t * t * t;
    return Key.linear(t, this, key2);
};

Key.easeOutQuart = function (t, key2)
{
    // return -c * ((t=t/d-1)*t*t*t - 1) + b;
    t = -1 * ((t -= 1) * t * t * t - 1);
    return Key.linear(t, this, key2);
};

Key.easeInOutQuart = function (t, key2)
{
    if ((t /= 0.5) < 1) t = 0.5 * t * t * t * t;
    else t = -0.5 * ((t -= 2) * t * t * t - 2);
    return Key.linear(t, this, key2);
};

Key.bounce = function (t)
{
    if ((t /= 1) < 1 / 2.75) t = 7.5625 * t * t;
    else if (t < 2 / 2.75) t = 7.5625 * (t -= 1.5 / 2.75) * t + 0.75;
    else if (t < 2.5 / 2.75) t = 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375;
    else t = 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375;
    return t;
};

Key.easeInBounce = function (t, key2)
{
    return Key.linear(Key.bounce(t), this, key2);
    // return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d);
};

Key.easeOutBounce = function (t, key2)
{
    return Key.linear(Key.bounce(t), this, key2);
};

Key.easeInElastic = function (t, key2)
{
    let s = 1.70158;
    let p = 0;
    let a = 1;

    const b = 0;
    const d = 1;
    const c = 1;

    if (t === 0) t = b;
    else if ((t /= d) == 1) t = b + c;
    else
    {
        if (!p) p = d * 0.3;
        if (a < Math.abs(c))
        {
            a = c;
            s = p / 4;
        }
        else s = (p / (2 * Math.PI)) * Math.asin(c / a);
        t = -(a * 2 ** (10 * (t -= 1)) * Math.sin(((t * d - s) * (2 * Math.PI)) / p)) + b;
    }

    return Key.linear(t, this, key2);
};


Key.easeOutElastic = function (t, key2)
{
    let s = 1.70158;
    let p = 0;
    let a = 1;

    const b = 0;
    const d = 1;
    const c = 1;

    if (t === 0) t = b;
    else if ((t /= d) == 1) t = b + c;
    else
    {
        if (!p) p = d * 0.3;
        if (a < Math.abs(c))
        {
            a = c;
            s = p / 4;
        }
        else s = (p / (2 * Math.PI)) * Math.asin(c / a);
        t = a * 2 ** (-10 * t) * Math.sin(((t * d - s) * (2 * Math.PI)) / p) + c + b;
    }

    return Key.linear(t, this, key2);
};

Key.easeInBack = function (t, key2)
{
    const s = 1.70158;
    t = t * t * ((s + 1) * t - s);

    return Key.linear(t, this, key2);
};

Key.easeOutBack = function (t, key2)
{
    const s = 1.70158;
    t = (t = t / 1 - 1) * t * ((s + 1) * t + s) + 1;

    return Key.linear(t, this, key2);
};

Key.easeInOutBack = function (t, key2)
{
    let s = 1.70158;
    const c = 1 / 2;
    if ((t /= 1 / 2) < 1) t = c * (t * t * (((s *= 1.525) + 1) * t - s));
    else t = c * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2);

    return Key.linear(t, this, key2);
};

const easeCubicOut = function (t)
{
    t--;
    t = t * t * t + 1;
    return t;
};

Key.easeCubicOut = function (t, key2)
{
    t = easeCubicOut(t);
    return Key.linear(t, this, key2);
};

const easeCubicInOut = function (t)
{
    t *= 2;
    if (t < 1) t = 0.5 * t * t * t;
    else
    {
        t -= 2;
        t = 0.5 * (t * t * t + 2);
    }
    return t;
};

Key.easeCubicInOut = function (t, key2)
{
    t = easeCubicInOut(t);
    return Key.linear(t, this, key2);
};

Key.easeSmoothStep = function (perc, key2)
{
    // var x = Math.max(0, Math.min(1, (perc-0)/(1-0)));
    const x = Math.max(0, Math.min(1, perc));
    perc = x * x * (3 - 2 * x); // smoothstep
    return Key.linear(perc, this, key2);
};

Key.easeSmootherStep = function (perc, key2)
{
    const x = Math.max(0, Math.min(1, (perc - 0) / (1 - 0)));
    perc = x * x * x * (x * (x * 6 - 15) + 10); // smootherstep
    return Key.linear(perc, this, key2);
};

Key.prototype.setEasing = function (e)
{
    this._easing = e;

    if (this._easing == CONSTANTS.ANIM.EASING_LINEAR) this.ease = Key.easeLinear;
    else if (this._easing == CONSTANTS.ANIM.EASING_ABSOLUTE) this.ease = Key.easeAbsolute;
    else if (this._easing == CONSTANTS.ANIM.EASING_SMOOTHSTEP) this.ease = Key.easeSmoothStep;
    else if (this._easing == CONSTANTS.ANIM.EASING_SMOOTHERSTEP) this.ease = Key.easeSmootherStep;
    else if (this._easing == CONSTANTS.ANIM.EASING_CUBIC_IN) this.ease = Key.easeCubicIn;
    else if (this._easing == CONSTANTS.ANIM.EASING_CUBIC_OUT) this.ease = Key.easeCubicOut;
    else if (this._easing == CONSTANTS.ANIM.EASING_CUBIC_INOUT) this.ease = Key.easeCubicInOut;
    else if (this._easing == CONSTANTS.ANIM.EASING_EXPO_IN) this.ease = Key.easeExpoIn;
    else if (this._easing == CONSTANTS.ANIM.EASING_EXPO_OUT) this.ease = Key.easeExpoOut;
    else if (this._easing == CONSTANTS.ANIM.EASING_EXPO_INOUT) this.ease = Key.easeExpoInOut;
    else if (this._easing == CONSTANTS.ANIM.EASING_SIN_IN) this.ease = Key.easeSinIn;
    else if (this._easing == CONSTANTS.ANIM.EASING_SIN_OUT) this.ease = Key.easeSinOut;
    else if (this._easing == CONSTANTS.ANIM.EASING_SIN_INOUT) this.ease = Key.easeSinInOut;
    else if (this._easing == CONSTANTS.ANIM.EASING_BACK_OUT) this.ease = Key.easeOutBack;
    else if (this._easing == CONSTANTS.ANIM.EASING_BACK_IN) this.ease = Key.easeInBack;
    else if (this._easing == CONSTANTS.ANIM.EASING_BACK_INOUT) this.ease = Key.easeInOutBack;
    else if (this._easing == CONSTANTS.ANIM.EASING_ELASTIC_IN) this.ease = Key.easeInElastic;
    else if (this._easing == CONSTANTS.ANIM.EASING_ELASTIC_OUT) this.ease = Key.easeOutElastic;
    else if (this._easing == CONSTANTS.ANIM.EASING_ELASTIC_INOUT) this.ease = Key.easeElasticInOut;
    else if (this._easing == CONSTANTS.ANIM.EASING_BOUNCE_IN) this.ease = Key.easeInBounce;
    else if (this._easing == CONSTANTS.ANIM.EASING_BOUNCE_OUT) this.ease = Key.easeOutBounce;
    else if (this._easing == CONSTANTS.ANIM.EASING_QUART_OUT) this.ease = Key.easeOutQuart;
    else if (this._easing == CONSTANTS.ANIM.EASING_QUART_IN) this.ease = Key.easeInQuart;
    else if (this._easing == CONSTANTS.ANIM.EASING_QUART_INOUT) this.ease = Key.easeInOutQuart;
    else if (this._easing == CONSTANTS.ANIM.EASING_QUINT_OUT) this.ease = Key.easeOutQuint;
    else if (this._easing == CONSTANTS.ANIM.EASING_QUINT_IN) this.ease = Key.easeInQuint;
    else if (this._easing == CONSTANTS.ANIM.EASING_QUINT_INOUT) this.ease = Key.easeInOutQuint;
    else if (this._easing == CONSTANTS.ANIM.EASING_CUBICSPLINE)
    {
        // this._updateBezier = true;
        this.ease = Key.easeCubicSpline;
    }
    else
    {
        this._easing = CONSTANTS.ANIM.EASING_LINEAR;
        this.ease = Key.easeLinear;
    }
};

Key.prototype.trigger = function ()
{
    this.cb();
    this.cbTriggered = true;
};

Key.prototype.setValue = function (v)
{
    this.value = v;
    // this._updateBezier = true;
    if (this.onChange !== null) this.onChange();
};

Key.prototype.set = function (obj)
{
    if (obj)
    {
        if (obj.e) this.setEasing(obj.e);
        if (obj.cb)
        {
            this.cb = obj.cb;
            this.cbTriggered = false;
        }

        if (obj.b)
        {
            // this.bezTime = obj.b[0];
            // this.bezValue = obj.b[1];
            // this.bezTimeIn = obj.b[2];
            // this.bezValueIn = obj.b[3];
            // this._updateBezier = true;
        }

        if (obj.hasOwnProperty("t")) this.time = obj.t;
        if (obj.hasOwnProperty("time")) this.time = obj.time;
        if (obj.hasOwnProperty("v")) this.value = obj.v;
        else if (obj.hasOwnProperty("value")) this.value = obj.value;
    }
    if (this.onChange !== null) this.onChange();
};

Key.prototype.getSerialized = function ()
{
    const obj = {};
    obj.t = this.time;
    obj.v = this.value;
    obj.e = this._easing;
    // if (this._easing == CONSTANTS.ANIM.EASING_CUBICSPLINE) obj.b = [this.bezTime, this.bezValue, this.bezTimeIn, this.bezValueIn];

    return obj;
};

Key.prototype.getEasing = function ()
{
    return this._easing;
};



;// CONCATENATED MODULE: ./src/core/eventtarget.js


const EventTarget = function ()
{
    this._log = new Logger("eventtarget");
    this._eventCallbacks = {};
    this._logName = "";
    this._logEvents = false;
    this._listeners = {};

    this.addEventListener = this.on = function (which, cb, idPrefix)
    {
        const event =
        {
            "id": (idPrefix || "") + CABLES.simpleId(),
            "name": which,
            "cb": cb,
        };
        if (!this._eventCallbacks[which]) this._eventCallbacks[which] = [event];
        else this._eventCallbacks[which].push(event);

        this._listeners[event.id] = event;

        return event.id;
    };

    this.hasEventListener = function (which, cb)
    {
        if (which && !cb)
        {
            // check by id
            if (this._listeners[which]) return true;
            else return false;
        }
        else
        {
            this._log.warn("old eventtarget function haseventlistener!");
            if (which && cb)
            {
                if (this._eventCallbacks[which])
                {
                    const idx = this._eventCallbacks[which].indexOf(cb);
                    if (idx == -1) return false;
                    return true;
                }
            }
        }
    };

    this.hasListenerForEventName = function (eventName)
    {
        return this._eventCallbacks[eventName] && this._eventCallbacks[eventName].length > 0;
    };

    this.removeEventListener = this.off = function (which, cb)
    {
        if (which === null || which === undefined) return;

        if (!cb) // new style, remove by id, not by name/callback
        {
            const event = this._listeners[which];
            if (!event)
            {
                this._log.log("removeEvent: could not find event...", which, this);
                return;
            }

            let found = true;
            while (found)
            {
                found = false;
                let index = -1;
                for (let i = 0; i < this._eventCallbacks[event.name].length; i++)
                {
                    if (this._eventCallbacks[event.name][i].id.startsWith(which)) // this._eventCallbacks[event.name][i].id == which ||
                    {
                        found = true;
                        index = i;
                    }
                }

                if (index !== -1)
                {
                    this._eventCallbacks[event.name].splice(index, 1);
                    delete this._listeners[which];
                }
            }

            return;
        }

        this._log.info("[eventtaget] ", "old function signature: removeEventListener! use listener id");
        this._log.log((new Error()).stack);

        let index = null;
        for (let i = 0; i < this._eventCallbacks[which].length; i++)
            if (this._eventCallbacks[which][i].cb == cb)
                index = i;

        if (index !== null)
        {
            delete this._eventCallbacks[index];
        }
        else this._log.warn("removeEventListener not found " + which);
    };

    this.logEvents = function (enabled, name)
    {
        this._logEvents = enabled;
        this._logName = name;
    };

    this.emitEvent = function (which, param1, param2, param3, param4, param5, param6)
    {
        if (this._logEvents) this._log.log("[event] ", this._logName, which, this._eventCallbacks);

        if (this._eventCallbacks[which])
        {
            for (let i = 0; i < this._eventCallbacks[which].length; i++)
            {
                if (this._eventCallbacks[which][i])
                {
                    this._eventCallbacks[which][i].cb(param1, param2, param3, param4, param5, param6);
                }
            }
        }
        else
        {
            if (this._logEvents) this._log.log("[event] has no event callback", which, this._eventCallbacks);
        }
    };
};



;// CONCATENATED MODULE: ./src/core/anim.js





/**
 * Keyframed interpolated animation.
 *
 * Available Easings:
 * <code>
 * CONSTANTS.ANIM.EASING_LINEAR
 * CONSTANTS.ANIM.EASING_ABSOLUTE
 * CONSTANTS.ANIM.EASING_SMOOTHSTEP
 * CONSTANTS.ANIM.EASING_SMOOTHERSTEP
 * CONSTANTS.ANIM.EASING_CUBICSPLINE

 * CONSTANTS.ANIM.EASING_CUBIC_IN
 * CONSTANTS.ANIM.EASING_CUBIC_OUT
 * CONSTANTS.ANIM.EASING_CUBIC_INOUT

 * CONSTANTS.ANIM.EASING_EXPO_IN
 * CONSTANTS.ANIM.EASING_EXPO_OUT
 * CONSTANTS.ANIM.EASING_EXPO_INOUT

 * CONSTANTS.ANIM.EASING_SIN_IN
 * CONSTANTS.ANIM.EASING_SIN_OUT
 * CONSTANTS.ANIM.EASING_SIN_INOUT

 * CONSTANTS.ANIM.EASING_BACK_IN
 * CONSTANTS.ANIM.EASING_BACK_OUT
 * CONSTANTS.ANIM.EASING_BACK_INOUT

 * CONSTANTS.ANIM.EASING_ELASTIC_IN
 * CONSTANTS.ANIM.EASING_ELASTIC_OUT

 * CONSTANTS.ANIM.EASING_BOUNCE_IN
 * CONSTANTS.ANIM.EASING_BOUNCE_OUT

 * CONSTANTS.ANIM.EASING_QUART_IN
 * CONSTANTS.ANIM.EASING_QUART_OUT
 * CONSTANTS.ANIM.EASING_QUART_INOUT

 * CONSTANTS.ANIM.EASING_QUINT_IN
 * CONSTANTS.ANIM.EASING_QUINT_OUT
 * CONSTANTS.ANIM.EASING_QUINT_INOUT
 * </code>
 * @class
 * @param cfg
 * @example
 * var anim=new CABLES.Anim();
 * anim.setValue(0,0);  // set value 0 at 0 seconds
 * anim.setValue(10,1); // set value 1 at 10 seconds
 * anim.getValue(5);    // get value at 5 seconds - this returns 0.5
 */

const Anim = function (cfg)
{
    EventTarget.apply(this);

    cfg = cfg || {};
    this.keys = [];
    this.onChange = null;
    this.stayInTimeline = false;
    this.loop = false;
    this._log = new Logger("Anim");
    this._lastKeyIndex = 0;
    this._cachedIndex = 0;
    this.name = cfg.name || null;

    /**
     * @member defaultEasing
     * @memberof Anim
     * @instance
     * @type {Number}
     */
    this.defaultEasing = cfg.defaultEasing || CONSTANTS.ANIM.EASING_LINEAR;
    this.onLooped = null;

    this._timesLooped = 0;
    this._needsSort = false;
};

Anim.prototype.forceChangeCallback = function ()
{
    if (this.onChange !== null) this.onChange();
    this.emitEvent("onChange", this);
};

Anim.prototype.getLoop = function ()
{
    return this.loop;
};

Anim.prototype.setLoop = function (target)
{
    this.loop = target;
    this.emitEvent("onChange", this);
};

/**
 * returns true if animation has ended at @time
 * checks if last key time is < time
 * @param {Number} time
 * @returns {Boolean}
 * @memberof Anim
 * @instance
 * @function
 */
Anim.prototype.hasEnded = function (time)
{
    if (this.keys.length === 0) return true;
    if (this.keys[this._lastKeyIndex].time <= time) return true;
    return false;
};

Anim.prototype.isRising = function (time)
{
    if (this.hasEnded(time)) return false;
    const ki = this.getKeyIndex(time);
    if (this.keys[ki].value < this.keys[ki + 1].value) return true;
    return false;
};

/**
 * remove all keys from animation before time
 * @param {Number} time
 * @memberof Anim
 * @instance
 * @function
 */
Anim.prototype.clearBefore = function (time)
{
    const v = this.getValue(time);
    const ki = this.getKeyIndex(time);

    this.setValue(time, v);

    if (ki > 1) this.keys.splice(0, ki);
    this._updateLastIndex();
};
/**
 * remove all keys from animation
 * @param {Number} [time=0] set a new key at time with the old value at time
 * @memberof Anim
 * @instance
 * @function
 */
Anim.prototype.clear = function (time)
{
    let v = 0;
    if (time) v = this.getValue(time);
    this.keys.length = 0;
    this._updateLastIndex();
    if (time) this.setValue(time, v);
    if (this.onChange !== null) this.onChange();
    this.emitEvent("onChange", this);
};

Anim.prototype.sortKeys = function ()
{
    this.keys.sort((a, b) => { return parseFloat(a.time) - parseFloat(b.time); });
    this._updateLastIndex();
    this._needsSort = false;
    if (this.keys.length % 1000 == 0)console.log(this.name, this.keys.length);
};

Anim.prototype.getLength = function ()
{
    if (this.keys.length === 0) return 0;
    return this.keys[this.keys.length - 1].time;
};

Anim.prototype.getKeyIndex = function (time)
{
    let index = 0;
    let start = 0;
    if (this._cachedIndex && this.keys.length > this._cachedIndex && time >= this.keys[this._cachedIndex].time) start = this._cachedIndex;
    for (let i = start; i < this.keys.length; i++)
    {
        if (time >= this.keys[i].time) index = i;
        if (this.keys[i].time > time)
        {
            if (time != 0) this._cachedIndex = index;
            return index;
        }
    }

    return index;
};

/**
 * set value at time
 * @function setValue
 * @memberof Anim
 * @instance
 * @param {Number} time
 * @param {Number} value
 * @param {Function} cb callback
 */
Anim.prototype.setValue = function (time, value, cb)
{
    let found = null;

    if (this.keys.length == 0 || time <= this.keys[this.keys.length - 1].time)
        for (let i = 0; i < this.keys.length; i++)
            if (this.keys[i].time == time)
            {
                found = this.keys[i];
                this.keys[i].setValue(value);
                this.keys[i].cb = cb;
                break;
            }

    if (!found)
    {
        found = new Key(
            {
                "time": time,
                "value": value,
                "e": this.defaultEasing,
                "cb": cb,
            });
        this.keys.push(found);

        // if (this.keys.length % 1000 == 0)console.log(this.name, this.keys.length);
        this._updateLastIndex();
    }

    if (this.onChange) this.onChange();
    this.emitEvent("onChange", this);
    this._needsSort = true;
    return found;
};

Anim.prototype.setKeyEasing = function (index, e)
{
    if (this.keys[index])
    {
        this.keys[index].setEasing(e);
        this.emitEvent("onChange", this);
    }
};

Anim.prototype.getSerialized = function ()
{
    const obj = {};
    obj.keys = [];
    obj.loop = this.loop;

    for (let i = 0; i < this.keys.length; i++)
        obj.keys.push(this.keys[i].getSerialized());

    return obj;
};

Anim.prototype.getKey = function (time)
{
    const index = this.getKeyIndex(time);
    return this.keys[index];
};

Anim.prototype.getNextKey = function (time)
{
    let index = this.getKeyIndex(time) + 1;
    if (index >= this.keys.length) index = this.keys.length - 1;

    return this.keys[index];
};

Anim.prototype.isFinished = function (time)
{
    if (this.keys.length <= 0) return true;
    return time > this.keys[this.keys.length - 1].time;
};

Anim.prototype.isStarted = function (time)
{
    if (this.keys.length <= 0) return false;
    return time >= this.keys[0].time;
};

/**
 * get value at time
 * @function getValue
 * @memberof Anim
 * @instance
 * @param {Number} [time] time
 * @returns {Number} interpolated value at time
 */
Anim.prototype.getValue = function (time)
{
    if (this.keys.length === 0)
    {
        return 0;
    }
    if (this._needsSort) this.sortKeys();

    if (!this.loop && time > this.keys[this._lastKeyIndex].time)
    {
        if (this.keys[this._lastKeyIndex].cb && !this.keys[this._lastKeyIndex].cbTriggered) this.keys[this._lastKeyIndex].trigger();

        return this.keys[this._lastKeyIndex].value;
    }

    if (time < this.keys[0].time)
    {
        // if (this.name)console.log("A");

        return this.keys[0].value;
    }

    if (this.loop && time > this.keys[this._lastKeyIndex].time)
    {
        const currentLoop = time / this.keys[this._lastKeyIndex].time;
        if (currentLoop > this._timesLooped)
        {
            this._timesLooped++;
            if (this.onLooped) this.onLooped();
        }
        time = (time - this.keys[0].time) % (this.keys[this._lastKeyIndex].time - this.keys[0].time);
        time += this.keys[0].time;
    }

    const index = this.getKeyIndex(time);
    if (index >= this._lastKeyIndex)
    {
        if (this.keys[this._lastKeyIndex].cb && !this.keys[this._lastKeyIndex].cbTriggered) this.keys[this._lastKeyIndex].trigger();

        return this.keys[this._lastKeyIndex].value;
    }


    const index2 = index + 1;
    const key1 = this.keys[index];
    const key2 = this.keys[index2];

    if (key1.cb && !key1.cbTriggered) key1.trigger();

    if (!key2) return -1;

    const perc = (time - key1.time) / (key2.time - key1.time);

    if (!key1.ease) this.log._warn("has no ease", key1, key2);

    return key1.ease(perc, key2);
};

Anim.prototype._updateLastIndex = function ()
{
    this._lastKeyIndex = this.keys.length - 1;
};

Anim.prototype.addKey = function (k)
{
    if (k.time === undefined)
    {
        this.log.warn("key time undefined, ignoring!");
    }
    else
    {
        this.keys.push(k);
        if (this.onChange !== null) this.onChange();
        this.emitEvent("onChange", this);
    }
    this._updateLastIndex();
};

Anim.prototype.easingFromString = function (str)
{
    if (str == "linear") return CONSTANTS.ANIM.EASING_LINEAR;
    if (str == "absolute") return CONSTANTS.ANIM.EASING_ABSOLUTE;
    if (str == "smoothstep") return CONSTANTS.ANIM.EASING_SMOOTHSTEP;
    if (str == "smootherstep") return CONSTANTS.ANIM.EASING_SMOOTHERSTEP;

    if (str == "Cubic In") return CONSTANTS.ANIM.EASING_CUBIC_IN;
    if (str == "Cubic Out") return CONSTANTS.ANIM.EASING_CUBIC_OUT;
    if (str == "Cubic In Out") return CONSTANTS.ANIM.EASING_CUBIC_INOUT;

    if (str == "Expo In") return CONSTANTS.ANIM.EASING_EXPO_IN;
    if (str == "Expo Out") return CONSTANTS.ANIM.EASING_EXPO_OUT;
    if (str == "Expo In Out") return CONSTANTS.ANIM.EASING_EXPO_INOUT;

    if (str == "Sin In") return CONSTANTS.ANIM.EASING_SIN_IN;
    if (str == "Sin Out") return CONSTANTS.ANIM.EASING_SIN_OUT;
    if (str == "Sin In Out") return CONSTANTS.ANIM.EASING_SIN_INOUT;

    if (str == "Back In") return CONSTANTS.ANIM.EASING_BACK_IN;
    if (str == "Back Out") return CONSTANTS.ANIM.EASING_BACK_OUT;
    if (str == "Back In Out") return CONSTANTS.ANIM.EASING_BACK_INOUT;

    if (str == "Elastic In") return CONSTANTS.ANIM.EASING_ELASTIC_IN;
    if (str == "Elastic Out") return CONSTANTS.ANIM.EASING_ELASTIC_OUT;

    if (str == "Bounce In") return CONSTANTS.ANIM.EASING_BOUNCE_IN;
    if (str == "Bounce Out") return CONSTANTS.ANIM.EASING_BOUNCE_OUT;

    if (str == "Quart Out") return CONSTANTS.ANIM.EASING_QUART_OUT;
    if (str == "Quart In") return CONSTANTS.ANIM.EASING_QUART_IN;
    if (str == "Quart In Out") return CONSTANTS.ANIM.EASING_QUART_INOUT;

    if (str == "Quint Out") return CONSTANTS.ANIM.EASING_QUINT_OUT;
    if (str == "Quint In") return CONSTANTS.ANIM.EASING_QUINT_IN;
    if (str == "Quint In Out") return CONSTANTS.ANIM.EASING_QUINT_INOUT;
};

Anim.prototype.createPort = function (op, title, cb)
{
    const port = op.inDropDown(title, CONSTANTS.ANIM.EASINGS, "Cubic Out");

    // const port = op.addInPort(
    //     new Port(op, title, CONSTANTS.OP.OP_PORT_TYPE_VALUE, {
    //         "display": "dropdown",
    //         "values": CONSTANTS.ANIM.EASINGS,
    //     }),
    // );

    port.set("linear");
    port.defaultValue = "linear";

    port.onChange = function ()
    {
        this.defaultEasing = this.easingFromString(port.get());
        this.emitEvent("onChangeDefaultEasing", this);

        if (cb) cb();
    }.bind(this);

    return port;
};

// ------------------------------

Anim.slerpQuaternion = function (time, q, animx, animy, animz, animw)
{
    if (!Anim.slerpQuaternion.q1)
    {
        Anim.slerpQuaternion.q1 = quat.create();
        Anim.slerpQuaternion.q2 = quat.create();
    }

    const i1 = animx.getKeyIndex(time);
    let i2 = i1 + 1;
    if (i2 >= animx.keys.length) i2 = animx.keys.length - 1;

    if (i1 == i2)
    {
        quat.set(q, animx.keys[i1].value, animy.keys[i1].value, animz.keys[i1].value, animw.keys[i1].value);
    }
    else
    {
        const key1Time = animx.keys[i1].time;
        const key2Time = animx.keys[i2].time;
        const perc = (time - key1Time) / (key2Time - key1Time);

        quat.set(Anim.slerpQuaternion.q1, animx.keys[i1].value, animy.keys[i1].value, animz.keys[i1].value, animw.keys[i1].value);

        quat.set(Anim.slerpQuaternion.q2, animx.keys[i2].value, animy.keys[i2].value, animz.keys[i2].value, animw.keys[i2].value);

        quat.slerp(q, Anim.slerpQuaternion.q1, Anim.slerpQuaternion.q2, perc);
    }
    return q;
};

const ANIM = { "Key": Key };




;// CONCATENATED MODULE: ./src/core/core_link.js



/**
 * @namespace external:CABLES#Link
 * @param {Object} scene The patch object
 * @description a link is a connection between two ops/ports -> one input and one output port
 * @hideconstructor
 * @class
 */
const Link = function (scene)
{
    EventTarget.apply(this);

    this.id = CABLES.simpleId();
    this.portIn = null;
    this.portOut = null;
    this.scene = scene; // todo: make private and rename to patch
    this.activityCounter = 0;
    this.ignoreInSerialize = false;
};

Link.prototype.setValue = function (v)
{
    if (v === undefined) this._setValue();
    else this.portIn.set(v);
};

Link.prototype.activity = function ()
{
    this.activityCounter++;
    // if(Date.now()-this.lastTime>100)
    // {
    //     // this.lastTime=Date.now();
    //     // this.changesPerSecond=this.changesCounter*10;
    //     this.changesCounter=0;
    // }
};

Link.prototype._setValue = function ()
{
    if (!this.portOut)
    {
        this.remove();
        return;
    }
    const v = this.portOut.get();

    if (v == v) // NaN is the only JavaScript value that is treated as unequal to itself
    {
        if (this.portIn.type != CONSTANTS.OP.OP_PORT_TYPE_FUNCTION) this.activity();

        if (this.portIn.get() !== v)
        {
            this.portIn.set(v);
        }
        else
        {
            if (this.portIn.changeAlways) this.portIn.set(v);
            if (this.portOut.forceRefChange) this.portIn.forceChange();
        }
    }
};

/**
 * @function getOtherPort
 * @memberof Link
 * @instance
 * @param {Port} p port
 * @description returns the port of the link, which is not port
 */
Link.prototype.getOtherPort = function (p)
{
    if (p == this.portIn) return this.portOut;
    return this.portIn;
};

/**
 * @function remove
 * @memberof Link
 * @instance
 * @description unlink/remove this link from all ports
 */
Link.prototype.remove = function ()
{
    if (this.portIn) this.portIn.removeLink(this);
    if (this.portOut) this.portOut.removeLink(this);
    if (this.scene)
    {
        this.scene.emitEvent("onUnLink", this.portIn, this.portOut, this);
    }

    if (this.portIn && (this.portIn.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT || this.portIn.type == CONSTANTS.OP.OP_PORT_TYPE_ARRAY))
    {
        this.portIn.set(null);
        if (this.portIn.links.length > 0) this.portIn.set(this.portIn.links[0].getOtherPort(this.portIn).get());
    }

    if (this.portIn) this.portIn.op._checkLinksNeededToWork();
    if (this.portOut) this.portOut.op._checkLinksNeededToWork();

    this.portIn = null;
    this.portOut = null;
    this.scene = null;
};

/**
 * @function link
 * @memberof Link
 * @instance
 * @description link those two ports
 * @param {Port} p1 port1
 * @param {Port} p2 port2
 */
Link.prototype.link = function (p1, p2)
{
    if (!Link.canLink(p1, p2))
    {
        console.warn("[core_link] cannot link ports!", p1, p2);
        return false;
    }

    if (p1.direction == CONSTANTS.PORT.PORT_DIR_IN)
    {
        this.portIn = p1;
        this.portOut = p2;
    }
    else
    {
        this.portIn = p2;
        this.portOut = p1;
    }

    p1.addLink(this);
    p2.addLink(this);

    this.setValue();

    if (p1.onLink) p1.onLink(this);
    if (p2.onLink) p2.onLink(this);

    p1.op._checkLinksNeededToWork();
    p2.op._checkLinksNeededToWork();
};

Link.prototype.getSerialized = function ()
{
    const obj = {};

    obj.portIn = this.portIn.getName();
    obj.portOut = this.portOut.getName();
    obj.objIn = this.portIn.op.id;
    obj.objOut = this.portOut.op.id;

    return obj;
};

// --------------------------------------------

/**
 * @function canLinkText
 * @memberof Link
 * @instance
 * @description return a text message with human readable reason if ports can not be linked, or can be
 * @param {Port} p1 port1
 * @param {Port} p2 port2
 */
Link.canLinkText = function (p1, p2)
{
    if (p1.direction == p2.direction)
    {
        let txt = "(out)";
        if (p2.direction == CONSTANTS.PORT.PORT_DIR_IN) txt = "(in)";
        return "can not link: same direction " + txt;
    }
    if (p1.op == p2.op) return "can not link: same op";
    if (p1.type != CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC && p2.type != CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC)
    {
        if (p1.type != p2.type) return "can not link: different type";
    }

    if (CABLES.UI && p1.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT && p2.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT)
    {
        if (p1.uiAttribs.objType && p2.uiAttribs.objType)
            if (p1.uiAttribs.objType != p2.uiAttribs.objType)
                return "incompatible objects";
    }


    if (!p1) return "can not link: port 1 invalid";
    if (!p2) return "can not link: port 2 invalid";

    if (p1.direction == CONSTANTS.PORT.PORT_DIR_IN && p1.isAnimated()) return "can not link: is animated";
    if (p2.direction == CONSTANTS.PORT.PORT_DIR_IN && p2.isAnimated()) return "can not link: is animated";

    // if(p1.direction==CABLES.CONSTANTS.PORT.PORT_DIR_IN && p1.links.length>0)return 'input port already busy';
    // if(p2.direction==CABLES.CONSTANTS.PORT.PORT_DIR_IN && p2.links.length>0)return 'input port already busy';
    if (p1.isLinkedTo(p2)) return "ports already linked";

    if ((p1.canLink && !p1.canLink(p2)) || (p2.canLink && !p2.canLink(p1))) return "Incompatible";

    return "can link";
};

/**
 * @function canLink
 * @memberof Link
 * @instance
 * @description return true if ports can be linked
 * @param {Port} p1 port1
 * @param {Port} p2 port2
 * @returns {Boolean}
 */
Link.canLink = function (p1, p2)
{
    if (!p1) return false;
    if (!p2) return false;
    if (p1.direction == CONSTANTS.PORT.PORT_DIR_IN && p1.isAnimated()) return false;
    if (p2.direction == CONSTANTS.PORT.PORT_DIR_IN && p2.isAnimated()) return false;

    if (p1.isHidden() || p2.isHidden()) return false;

    if (p1.isLinkedTo(p2)) return false;

    if (p1.direction == p2.direction) return false;

    if (CABLES.UI && p1.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT && p2.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT)
    {
        if (p1.uiAttribs.objType && p2.uiAttribs.objType)
        {
            if (p1.uiAttribs.objType.indexOf("sg_") == 0 && p2.uiAttribs.objType.indexOf("sg_") == 0) return true;
            if (p1.uiAttribs.objType != p2.uiAttribs.objType)
                return false;
        }
    }

    if (p1.type != p2.type && (p1.type != CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC && p2.type != CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC)) return false;
    if (p1.type == CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC || p2.type == CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC) return true;

    if (p1.op == p2.op) return false;

    if (p1.canLink && !p1.canLink(p2)) return false;
    if (p2.canLink && !p2.canLink(p1)) return false;

    return true;
};



;// CONCATENATED MODULE: ./src/core/core_port.js







/**
 * data is coming into and out of ops through input and output ports
 * @namespace external:CABLES#Port
 * @class
 * @hideconstructor
 * @param ___op
 * @param name
 * @param type
 * @param uiAttribs
 * @example
 * const myPort=op.inString("String Port");
 */
const Port = function (___op, name, type, uiAttribs)
{
    EventTarget.apply(this);

    this.data = {}; // UNUSED, DEPRECATED, only left in for backwards compatibility with userops
    this._log = new Logger("core_port");
    /**
     * @type {Number}
     * @name direction
     * @instance
     * @memberof Port
     * @description direction of port (input(0) or output(1))
     */
    this.direction = CONSTANTS.PORT.PORT_DIR_IN;
    this.id = String(CABLES.simpleId());
    this._op = ___op;

    /**
     * @type {Array<Link>}
     * @name links
     * @instance
     * @memberof Port
     * @description links of port
     */
    this.links = [];
    this.value = 0.0;
    this.name = name;
    this.type = type || CONSTANTS.OP.OP_PORT_TYPE_VALUE;
    this.uiAttribs = uiAttribs || {};
    this.anim = null;
    this._oldAnimVal = -5711;
    this.defaultValue = null;


    this._uiActiveState = true;
    this.ignoreValueSerialize = false;
    this.onLinkChanged = null;
    this.crashed = false;

    this._valueBeforeLink = null;
    this._lastAnimFrame = -1;
    this._animated = false;

    this.onValueChanged = null;
    this.onTriggered = null;
    this.onUiActiveStateChange = null;
    this.changeAlways = false;
    this.forceRefChange = false;

    this._useVariableName = null;

    this.activityCounter = 0;
    this.apf = 0;
    this.activityCounterStartFrame = 0;

    this._tempLastUiValue = null;

    Object.defineProperty(this, "title", {
        get()
        {
            return this.uiAttribs.title || this.name;
        } });

    Object.defineProperty(this, "parent", {
        get()
        {
            this._log.stack("use port.op, not .parent");
            return this._op;
        } });

    Object.defineProperty(this, "op", {
        get()
        {
            return this._op;
        } });

    Object.defineProperty(this, "val", {
        get()
        {
            // this._log.warn("val getter deprecated!", this);
            // this._log.stack("val getter deprecated");
            return this.get();
        },
        set(v)
        {
            // this._log.warn("val setter deprecated!", this);
            // this._log.stack("val setter deprecated");
            this.setValue(v);
        }
    });
};


/**
 * copy over a uiattrib from an external connected port to another port
 * @function copyLinkedUiAttrib
 * @memberof Port
 * @param {string} which attrib name
 * @param {Port} port source port
 * @instance
 * @example

inArray.onLinkChanged=()=>
{
    if(inArray) inArray.copyLinkedUiAttrib("stride", outArray);
};

 */
Port.prototype.copyLinkedUiAttrib = function (which, port)
{
    if (!CABLES.UI) return;
    if (!this.isLinked()) return;

    const attr = {};
    attr[which] = this.links[0].getOtherPort(this).getUiAttrib(which);
    port.setUiAttribs(attr);
};


// TODO make extend class for ports, like for ops only for ui
Port.prototype.getValueForDisplay = function ()
{
    let str = this.value;

    if (typeof this.value === "string" || this.value instanceof String)
    {
        if (str.length > 1000)
        {
            str = str.substring(0, 999);
            str += "...";
        }
        if (this.uiAttribs && (this.uiAttribs.display == "boolnum"))
        {
            str += " - ";

            if (!this.value) str += "false";
            else str += "true";
        }

        str = str.replace(/[\u00A0-\u9999<>\&]/g, function (i)
        {
            return "&#" + i.charCodeAt(0) + ";";
        });


        if (str.length > 100) str = str.substring(0, 100);
    }
    else
    {
        str = this.value;
    }
    return str;
};

/**
 * change listener for input value ports, overwrite to react to changes
 * @function onChange
 * @memberof Port
 * @instance
 * @example
 * const myPort=op.inString("MyPort");
 * myPort.onChange=function()
 * {
 *   console.log("was changed to: ",myPort.get());
 * }
 *
 */
Port.prototype.onAnimToggle = function () {};
Port.prototype._onAnimToggle = function ()
{
    this.onAnimToggle();
};


/**
 * @function remove
 * @memberof Port
 * @instance
 * @description remove port
 */
Port.prototype.remove = function ()
{
    // this.setUiAttribs({ "hidePort": true });
    this.removeLinks();
    this._op.removePort(this);
};

/**
 * set ui attributes
 * @function setUiAttribs
 * @memberof Port
 * @instance
 * @param {Object} newAttribs
 * <pre>
 * title - overwrite title of port (by default this is portname)
 * greyout - port paramater will appear greyed out, can not be
 * hidePort - port will be hidden from op
 * hideParam - port params will be hidden from parameter panel
 * showIndex - only for dropdowns - show value index (e.g. `0 - normal` )
 * editorSyntax - set syntax highlighting theme for editor port
 * ignoreObjTypeErrors - do not auto check object types
 * </pre>
 * @example
 * myPort.setUiAttribs({greyout:true});
 */
Port.prototype.setUiAttribs = function (newAttribs)
{
    let changed = false;
    if (!this.uiAttribs) this.uiAttribs = {};

    for (const p in newAttribs)
    {
        if (newAttribs[p] === undefined)
        {
            // delete newAttribs[p];
            delete this.uiAttribs[p];
            continue;
        }
        if (this.uiAttribs[p] != newAttribs[p]) changed = true;
        this.uiAttribs[p] = newAttribs[p];

        if (p == "group" && this.indexPort) this.indexPort.setUiAttribs({ "group": newAttribs[p] });
    }

    if (newAttribs.hasOwnProperty("expose")) this._op.patch.emitEvent("subpatchExpose", this._op.uiAttribs.subPatch);

    if (changed) this.emitEvent("onUiAttrChange", newAttribs, this);
};

/**
 * get ui attributes
 * @function getUiAttribs
 * @memberof Port
 * @example
 * myPort.getUiAttribs();
 */
Port.prototype.getUiAttribs = function ()
{
    return this.uiAttribs;
};

/**
 * get ui attribute
 * @function getUiAttrib
 * @memberof Port
 * @instance
 * @param {String} attribName
 * <pre>
 * attribName - return value of the ui-attribute, or null on unknown attribute
 * </pre>
 * @example
 * myPort.setUiAttribs("values");
 */
Port.prototype.getUiAttrib = function (attribName)
{
    if (!this.uiAttribs || !this.uiAttribs.hasOwnProperty(attribName))
    {
        return null;
    }
    return this.uiAttribs[attribName];
};

/**
 * @function get
 * @memberof Port
 * @instance
 * @description get value of port
 */
Port.prototype.get = function ()
{
    if (this._animated && this._lastAnimFrame != this._op.patch.getFrameNum())
    {
        this._lastAnimFrame = this._op.patch.getFrameNum();

        let animval = this.anim.getValue(this._op.patch.timer.getTime());

        if (this.value != animval)
        {
            this.value = animval;
            this._oldAnimVal = this.value;
            this.forceChange();
        }
    }

    return this.value;
};

Port.prototype.setRef = function (v)
{
    this.forceRefChange = true;
    this.set(v);
};

/**
 * @function setValue
 * @memberof Port
 * @instance
 * @description set value of port / will send value to all linked ports (only for output ports)
 */
Port.prototype.set = Port.prototype.setValue = function (v)
{
    if (v === undefined) v = null;


    if (CABLES.UI && CABLES.UI.showDevInfos)
        if (this.direction == CONSTANTS.PORT.PORT_DIR_OUT && this.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT && v && !this.forceRefChange)
            this._log.warn("object port uses .set", this.name, this.op.objName);


    if (this._op.enabled && !this.crashed)
    {
        if (v !== this.value || this.changeAlways || this.type == CONSTANTS.OP.OP_PORT_TYPE_TEXTURE || this.type == CONSTANTS.OP.OP_PORT_TYPE_ARRAY)
        {
            if (this._animated)
            {
                this.anim.setValue(this._op.patch.timer.getTime(), v);
            }
            else
            {
                try
                {
                    this.value = v;
                    this.forceChange();
                }
                catch (ex)
                {
                    this.crashed = true;

                    this.setValue = function (_v) {};
                    this.onTriggered = function () {};

                    this._log.error("exception in ", this._op);
                    this._log.error(ex);

                    this._op.patch.emitEvent("exception", ex, this._op);
                }

                if (this._op && this._op.patch && this._op.patch.isEditorMode() && this.type == CONSTANTS.OP.OP_PORT_TYPE_TEXTURE) gui.texturePreview().updateTexturePort(this);
            }

            if (this.direction == CONSTANTS.PORT.PORT_DIR_OUT) for (let i = 0; i < this.links.length; ++i) this.links[i].setValue();
        }
    }
};

Port.prototype.updateAnim = function ()
{
    if (this._animated)
    {
        this.value = this.get();

        if (this._oldAnimVal != this.value || this.changeAlways)
        {
            this._oldAnimVal = this.value;
            this.forceChange();
        }
        this._oldAnimVal = this.value;
    }
};

Port.prototype.forceChange = function ()
{
    if (this.onValueChanged || this.onChange)
    {
        // very temporary: deprecated warning!!!!!!!!!
        // if(params.length>0) this._log.warn('TOM: port has onchange params!',this._op.objName,this.name);
    }
    this._activity();
    this.emitEvent("change", this.value, this);

    // try
    // {
    if (this.onChange) this.onChange(this, this.value);
    else if (this.onValueChanged) this.onValueChanged(this, this.value); // deprecated
    // }
    // catch (e)
    // {
    //     console.log(e);
    // }
};

/**
 * @function getTypeString
 * @memberof Port
 * @instance
 * @description get port type as string, e.g. "Function","Value"...
 * @return {String} type
 */
Port.prototype.getTypeString = function ()
{
    if (this.type == CONSTANTS.OP.OP_PORT_TYPE_VALUE) return "Number";
    if (this.type == CONSTANTS.OP.OP_PORT_TYPE_FUNCTION) return "Trigger";
    if (this.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT) return "Object";
    if (this.type == CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC) return "Dynamic";
    if (this.type == CONSTANTS.OP.OP_PORT_TYPE_ARRAY) return "Array";
    if (this.type == CONSTANTS.OP.OP_PORT_TYPE_STRING) return "String";
    return "Unknown";
};

Port.prototype.deSerializeSettings = function (objPort)
{
    if (!objPort) return;
    if (objPort.animated) this.setAnimated(objPort.animated);
    if (objPort.useVariable) this.setVariableName(objPort.useVariable);
    if (objPort.title) this.setUiAttribs({ "title": objPort.title });
    if (objPort.expose) this.setUiAttribs({ "expose": true });
    if (objPort.order) this.setUiAttribs({ "order": objPort.order });

    if (objPort.multiPortManual) this.setUiAttribs({ "multiPortManual": objPort.multiPortManual });
    if (objPort.multiPortNum) this.setUiAttribs({ "multiPortNum": objPort.multiPortNum });

    if (objPort.anim)
    {
        if (!this.anim) this.anim = new Anim({ "name": "port " + this.name });
        this._op._hasAnimPort = true;
        this.anim.addEventListener("onChange", () =>
        {
            this._op.patch.emitEvent("portAnimUpdated", this._op, this, this.anim);
        });
        if (objPort.anim.loop) this.anim.loop = objPort.anim.loop;
        for (const ani in objPort.anim.keys)
        {
            this.anim.keys.push(new ANIM.Key(objPort.anim.keys[ani]));
        }
        this.anim.sortKeys();
    }
};


Port.prototype.setInitialValue = function (v)
{
    if (this.op.preservedPortLinks[this.name])
    {
        for (let i = 0; i < this.op.preservedPortLinks[this.name].length; i++)
        {
            const lobj = this.op.preservedPortLinks[this.name][i];
            this.op.patch._addLink(
                lobj.objIn,
                lobj.objOut,
                lobj.portIn,
                lobj.portOut);
        }
    }


    if (this.op.preservedPortValues && this.op.preservedPortValues.hasOwnProperty(this.name) && this.op.preservedPortValues[this.name] !== undefined)
    {
        this.set(this.op.preservedPortValues[this.name]);
    }
    else
    if (v !== undefined) this.set(v);
    if (v !== undefined) this.defaultValue = v;
};




Port.prototype.getSerialized = function ()
{
    let obj = { "name": this.getName() };


    if (!this.ignoreValueSerialize && this.links.length === 0)
    {
        if (this.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT && this.value && this.value.tex) {}
        else obj.value = this.value;
    }
    if (this._useVariableName) obj.useVariable = this._useVariableName;
    if (this._animated) obj.animated = true;
    if (this.anim) obj.anim = this.anim.getSerialized();
    if (this.uiAttribs.multiPortNum) obj.multiPortNum = this.uiAttribs.multiPortNum;
    if (this.uiAttribs.multiPortManual) obj.multiPortManual = this.uiAttribs.multiPortManual;

    if (this.uiAttribs.display == "file") obj.display = this.uiAttribs.display;
    if (this.uiAttribs.expose)
    {
        obj.expose = true;
        if (this.uiAttribs.hasOwnProperty("order")) obj.order = this.uiAttribs.order;
    }
    if (this.uiAttribs.title) obj.title = this.uiAttribs.title;
    if ((this.preserveLinks || this.direction == CONSTANTS.PORT.PORT_DIR_OUT) && this.links.length > 0)
    {
        obj.links = [];
        for (const i in this.links)
        {
            if (!this.links[i].ignoreInSerialize && (this.links[i].portIn && this.links[i].portOut)) obj.links.push(this.links[i].getSerialized());
        }
    }

    if (this.direction == CONSTANTS.PORT.PORT_DIR_IN && this.links.length > 0)
    {
        for (const i in this.links)
        {
            if (!this.links[i].portIn || !this.links[i].portOut) continue;

            const otherp = this.links[i].getOtherPort(this);
            // check if functions exist, are defined in core_extend_ops code in ui
            if (otherp.op.isInBlueprint2 && this.op.isInBlueprint2)
            {
                if (otherp.op.isInBlueprint2() && !this.op.isInBlueprint2())
                {
                    obj.links = obj.links || [];
                    obj.links.push(this.links[i].getSerialized());
                }
            }
        }
    }

    if (obj.links && obj.links.length == 0) delete obj.links;
    if (this.type === CONSTANTS.OP.OP_PORT_TYPE_FUNCTION) delete obj.value;
    if (this.type === CONSTANTS.OP.OP_PORT_TYPE_FUNCTION && this.links.length == 0) obj = null;
    if (obj && Object.keys(obj).length == 1 && obj.name)obj = null; // obj is null if there is no real information other than name

    // console.log(obj);
    cleanJson(obj);

    return obj;
};

Port.prototype.shouldLink = function ()
{
    return true;
};

/**
 * @function removeLinks
 * @memberof Port
 * @instance
 * @description remove all links from port
 */
Port.prototype.removeLinks = function ()
{
    let count = 0;
    while (this.links.length > 0)
    {
        count++;
        if (count > 5000)
        {
            this._log.warn("could not delete links... / infinite loop");
            this.links.length = 0;
            break;
        }
        this.links[0].remove();
    }
};

/**
 * @function removeLink
 * @memberof Port
 * @instance
 * @description remove all link from port
 * @param {CABLES.Link} link
 */
Port.prototype.removeLink = function (link)
{
    for (const i in this.links)
        if (this.links[i] == link)
            this.links.splice(i, 1);

    if (this.direction == CONSTANTS.PORT.PORT_DIR_IN)
    {
        if (this.type == CONSTANTS.OP.OP_PORT_TYPE_VALUE) this.setValue(this._valueBeforeLink || 0);
        else this.setValue(this._valueBeforeLink || null);
    }

    if (CABLES.UI && this._op.checkLinkTimeWarnings) this._op.checkLinkTimeWarnings();

    try
    {
        if (this.onLinkChanged) this.onLinkChanged();
        this.emitEvent("onLinkChanged");
        this.emitEvent("onLinkRemoved");
        this._op.emitEvent("onLinkChanged");
    }
    catch (e)
    {
        this._log.error(e);
    }
};

/**
 * @function getName
 * @memberof Port
 * @instance
 * @description return port name
 */
Port.prototype.getName = function ()
{
    return this.name;
};

/**
 * @function getTitle
 * @memberof Port
 * @instance
 * @description return port name or title
 */
Port.prototype.getTitle = function ()
{
    if (this.uiAttribs.title) return this.uiAttribs.title;
    return this.name;
};

Port.prototype.addLink = function (l)
{
    this._valueBeforeLink = this.value;
    this.links.push(l);
    if (CABLES.UI && this._op.checkLinkTimeWarnings) this._op.checkLinkTimeWarnings();

    try
    {
        if (this.onLinkChanged) this.onLinkChanged();
        this.emitEvent("onLinkChanged");
        this._op.emitEvent("onLinkChanged");
    }
    catch (e)
    {
        this._log.error(e);
    }
};

/**
 * @function getLinkTo
 * @memberof Port
 * @instance
 * @param {Port} p2 otherPort
 * @description return link, which is linked to otherPort
 */
Port.prototype.getLinkTo = function (p2)
{
    for (const i in this.links) if (this.links[i].portIn == p2 || this.links[i].portOut == p2) return this.links[i];
};

/**
 * @function removeLinkTo
 * @memberof Port
 * @instance
 * @param {Port} p2 otherPort
 * @description removes link, which is linked to otherPort
 */
Port.prototype.removeLinkTo = function (p2)
{
    for (const i in this.links)
    {
        if (this.links[i].portIn == p2 || this.links[i].portOut == p2)
        {
            this.links[i].remove();
            if (CABLES.UI && this._op.checkLinkTimeWarnings) this._op.checkLinkTimeWarnings();

            if (this.onLinkChanged) this.onLinkChanged();
            this.emitEvent("onLinkChanged");
            this.emitEvent("onLinkRemoved");
            return;
        }
    }
};

/**
 * @function isLinkedTo
 * @memberof Port
 * @instance
 * @param {Port} p2 otherPort
 * @description returns true if port is linked to otherPort
 */
Port.prototype.isLinkedTo = function (p2)
{
    for (const i in this.links) if (this.links[i].portIn == p2 || this.links[i].portOut == p2) return true;

    return false;
};

Port.prototype._activity = function ()
{
    this.activityCounter++;
};

/**
 * @function trigger
 * @memberof Port
 * @instance
 * @description trigger the linked port (usually invoked on an output function port)
 */
Port.prototype.trigger = function ()
{
    const linksLength = this.links.length;

    this._activity();
    if (linksLength === 0) return;
    if (!this._op.enabled) return;

    let portTriggered = null;
    try
    {
        for (let i = 0; i < linksLength; ++i)
        {
            if (this.links[i].portIn)
            {
                portTriggered = this.links[i].portIn;

                portTriggered.op.patch.pushTriggerStack(portTriggered);
                portTriggered._onTriggered();

                portTriggered.op.patch.popTriggerStack();
            }
            if (this.links[i]) this.links[i].activity();
        }
    }
    catch (ex)
    {
        portTriggered.op.enabled = false;

        if (this._op.patch.isEditorMode())
        {
            // this._op.patch.emitEvent("exception", ex, portTriggered.op);
            // this._op.patch.emitEvent("opcrash", portTriggered);
            // console.log("crash", portTriggered.op.objName);

            if (portTriggered.op.onError) portTriggered.op.onError(ex);
        }
        this._log.error("exception in port: ", portTriggered.name, portTriggered.op.name, portTriggered.op);
        this._log.error(ex);
    }
};

Port.prototype.call = function ()
{
    this._log.warn("call deprecated - use trigger() ");
    this.trigger();
};

Port.prototype.execute = function ()
{
    this._log.warn("### execute port: " + this.getName(), this.goals.length);
};

Port.prototype.setVariableName = function (n)
{
    this._useVariableName = n;


    this._op.patch.on("variableRename", (oldname, newname) =>
    {
        if (oldname != this._useVariableName) return;
        this._useVariableName = newname;
    });
};

Port.prototype.getVariableName = function ()
{
    return this._useVariableName;
};

Port.prototype.setVariable = function (v)
{
    this.setAnimated(false);
    const attr = { "useVariable": false };

    if (this._variableIn && this._varChangeListenerId)
    {
        this._variableIn.off(this._varChangeListenerId);
        this._variableIn = null;
    }

    if (v)
    {
        this._variableIn = this._op.patch.getVar(v);

        if (!this._variableIn)
        {
            this._log.warn("PORT VAR NOT FOUND!!!", v);
        }
        else
        {
            if (this.type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT)
            {
                this._varChangeListenerId = this._variableIn.on("change", () => { this.set(null); this.set(this._variableIn.getValue()); });
            }
            else
            {
                this._varChangeListenerId = this._variableIn.on("change", this.set.bind(this));
            }
            this.set(this._variableIn.getValue());
        }
        this._useVariableName = v;
        attr.useVariable = true;
        attr.variableName = this._useVariableName;
    }
    else
    {
        attr.variableName = this._useVariableName = null;
        attr.useVariable = false;
    }

    this.setUiAttribs(attr);
    this._op.patch.emitEvent("portSetVariable", this._op, this, v);
};

Port.prototype._handleNoTriggerOpAnimUpdates = function (a)
{
    let hasTriggerPort = false;
    for (let i = 0; i < this._op.portsIn.length; i++)
    {
        if (this._op.portsIn.type == CONSTANTS.OP.OP_PORT_TYPE_FUNCTION)
        {
            hasTriggerPort = true;
            break;
        }
    }

    if (!hasTriggerPort)
    {
        if (a) this._notriggerAnimUpdate = this._op.patch.on("onRenderFrame",
            () =>
            {
                this.updateAnim();
            });
        else this._op.patch.removeEventListener(this._notriggerAnimUpdate);
    }
};

Port.prototype.setAnimated = function (a)
{
    if (this._animated != a)
    {
        this._animated = a;
        this._op._hasAnimPort = true;

        if (this._animated && !this.anim)
        {
            this.anim = new Anim({ "name": "port " + this.name });
            this.anim.addEventListener("onChange", () =>
            {
                this._op.patch.emitEvent("portAnimUpdated", this._op, this, this.anim);
            });
        }
        this._onAnimToggle();
    }

    this._handleNoTriggerOpAnimUpdates(a);
    if (!a)
    {
        this.anim = null;
    }

    this.setUiAttribs({ "isAnimated": this._animated });
};

Port.prototype.toggleAnim = function ()
{
    this._animated = !this._animated;
    if (this._animated && !this.anim)
    {
        this.anim = new Anim({ "name": "port " + this.name });
        this.anim.addEventListener("onChange", () =>
        {
            this._op.patch.emitEvent("portAnimUpdated", this._op, this, this.anim);
        });
    }
    this.setAnimated(this._animated);
    this._onAnimToggle();
    this.setUiAttribs({ "isAnimated": this._animated });
};

/**
 * <pre>
 * CABLES.CONSTANTS.OP.OP_PORT_TYPE_VALUE = 0;
 * CABLES.CONSTANTS.OP.OP_PORT_TYPE_FUNCTION = 1;
 * CABLES.CONSTANTS.OP.OP_PORT_TYPE_OBJECT = 2;
 * CABLES.CONSTANTS.OP.OP_PORT_TYPE_TEXTURE = 2;
 * CABLES.CONSTANTS.OP.OP_PORT_TYPE_ARRAY = 3;
 * CABLES.CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC = 4;
 * CABLES.CONSTANTS.OP.OP_PORT_TYPE_STRING = 5;
 * </pre>
 * @function getType
 * @memberof Port
 * @instance
 * @return {Number} type of port
 */
Port.prototype.getType = function ()
{
    return this.type;
};

/**
 * @function isLinked
 * @memberof Port
 * @instance
 * @return {Boolean} true if port is linked
 */
Port.prototype.isLinked = function ()
{
    return this.links.length > 0 || this._animated || this._useVariableName != null;
};

Port.prototype.isBoundToVar = function ()
{
    const b = this._useVariableName != null;
    this.uiAttribs.boundToVar = b;
    return b;
};
/**
 * @function isAnimated
 * @memberof Port
 * @instance
 * @return {Boolean} true if port is animated
 */
Port.prototype.isAnimated = function ()
{
    return this._animated;
};

/**
 * @function isHidden
 * @memberof Port
 * @instance
 * @return {Boolean} true if port is hidden
 */
Port.prototype.isHidden = function ()
{
    return this.uiAttribs.hidePort;
};

/**
 * @function onTriggered
 * @memberof Port
 * @instance
 * @param {function} a onTriggeredCallback
 * @description set callback, which will be executed when port was triggered (usually output port)
 */
Port.prototype._onTriggered = function (a)
{
    this._activity();
    this._op.updateAnims();
    if (this._op.enabled && this.onTriggered) this.onTriggered(a);

    if (this._op.enabled) this.emitEvent("trigger");
};

Port.prototype._onSetProfiling = function (v)
{
    this._op.patch.profiler.add("port", this);
    this.setValue(v);
    this._op.patch.profiler.add("port", null);
};

Port.prototype._onTriggeredProfiling = function ()
{
    if (this._op.enabled && this.onTriggered)
    {
        this._op.patch.profiler.add("port", this);
        this.onTriggered();
        this._op.patch.profiler.add("port", null);
    }
};



Port.prototype.getUiActiveState = function ()
{
    return this._uiActiveState;
};

Port.prototype.setUiActiveState = function (onoff)
{
    this._uiActiveState = onoff;
    if (this.onUiActiveStateChange) this.onUiActiveStateChange();
};

/**
 * @deprecated
 * @param {function} cb
 */
Port.prototype.onValueChange = function (cb)
{
    this.onChange = cb;
};

/**
 * @deprecated
 */
Port.prototype.hidePort = function () {};


/**
 * Returns the port type string, e.g. "value" based on the port type number
 * @function portTypeNumberToString
 * @instance
 * @memberof Port
 * @param {Number} type - The port type number
 * @returns {String} - The port type as string
 */
Port.portTypeNumberToString = function (type)
{
    if (type == CONSTANTS.OP.OP_PORT_TYPE_VALUE) return "value";
    if (type == CONSTANTS.OP.OP_PORT_TYPE_FUNCTION) return "function";
    if (type == CONSTANTS.OP.OP_PORT_TYPE_OBJECT) return "object";
    if (type == CONSTANTS.OP.OP_PORT_TYPE_ARRAY) return "array";
    if (type == CONSTANTS.OP.OP_PORT_TYPE_STRING) return "string";
    if (type == CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC) return "dynamic";
    return "unknown";
};



;// CONCATENATED MODULE: ./src/core/core_port_switch.js




class SwitchPort extends Port
{
    constructor(__parent, name, type, uiAttribs, indexPort)
    {
        super(__parent, name, type, uiAttribs);

        this.get = () =>
        {
            let s = super.get();

            if (CABLES.UI)
            {
                if (
                    s === "" ||
                    s === null ||
                    s === undefined ||
                    (uiAttribs.values && uiAttribs.values.indexOf(String(s)) === -1)
                )
                {
                    this.op.setUiError("invalidswitch", "Invalid Value [" + this.name + "]: \"" + s + "\"", 1);
                }
                else this.op.setUiError("invalidswitch", null);
            }

            if (s === null || s === undefined)s = "";

            return s;
        };

        this.indexPort = indexPort;
        this.indexPort.set = (value) =>
        {
            const values = uiAttribs.values;

            if (!values)
            {
                // console.log("switch port has no values", this);
                return;
            }

            let intValue = Math.floor(value);

            intValue = Math.min(intValue, values.length - 1);
            intValue = Math.max(intValue, 0);

            this.indexPort.setValue(intValue);
            this.set(values[intValue]);

            if (this.op.patch.isEditorMode() && performance.now() - (this.lastTime || 0) > 100 && window.gui && gui.patchView.isCurrentOp(this.op))
            {
                gui.opParams.show(this.op);
                this.lastTime = performance.now();
            }
        };
    }

    setUiAttribs(attribs)
    {
        const hidePort = attribs.hidePort;
        attribs.hidePort = true;
        super.setUiAttribs(attribs);
        if (typeof hidePort !== "undefined")
        {
            this.indexPort.setUiAttribs({ hidePort });
        }
    }
}



;// CONCATENATED MODULE: ./src/core/core_port_select.js




class ValueSelectPort extends SwitchPort
{
    setUiAttribs(newAttribs)
    {
        // never unhide valuePort when indexPort is linked
        if (this.indexPort.isLinked())
        {
            for (const p in newAttribs)
            {
                if (p == "greyout" && !newAttribs[p]) newAttribs[p] = "true";
            }
        }
        super.setUiAttribs(newAttribs);
    }
}





;// CONCATENATED MODULE: ./src/core/core_port_multi.js



const MIN_NUM_PORTS = 2;

class MultiPort extends Port
{
    constructor(__parent, name, type, dir, uiAttribs, uiAttribsPorts)
    {
        super(__parent, name, CONSTANTS.OP.OP_PORT_TYPE_ARRAY, uiAttribs);

        this.setUiAttribs({ "multiPort": true, "group": this.name, "order": -1 });
        this.ports = [];
        this.direction = dir;
        this._uiAttribsPorts = uiAttribsPorts;

        // console.log("uiattribs", uiAttribs);

        const updateArray = () =>
        {
            const arr = [];

            let ll = 1;
            if (this.uiAttribs.multiPortManual)ll = 0;

            for (let i = 0; i < this.ports.length - ll; i++)
                arr[i] = this.ports[i];

            this.setRef(arr);
        };

        const updateUi = () =>
        {
            let grey = !this.uiAttribs.multiPortManual || undefined;

            if (this.direction == CONSTANTS.PORT.PORT_DIR_OUT)grey = false;

            for (let i = 0; i < this.ports.length; i++)
            {
                let lp; // undefined to remove/not set it
                // let opacity;// undefined to remove/not set it
                // let grey;// undefined to remove/not set it
                let addPort = false;
                let title;
                let o = {};


                // console.log("this.op.preservedPortTitles", this.op.preservedPortTitles, this.op.preservedPortTitles[po.name], po.name);
                if (this.op.preservedPortTitles && this.op.preservedPortTitles[this.ports[i].name]) title = this.op.preservedPortTitles[this.ports[i].name];


                // if (!this.uiAttribs.multiPortManual)grey = true;
                if (i == 0) lp = this.ports.length;

                if (!this.uiAttribs.multiPortManual)
                    if (i == this.ports.length - 1)
                    {
                        title = "add port";
                        addPort = true;
                        grey = true;
                    }

                for (const attin in this._uiAttribsPorts)
                {
                    o[attin] = this._uiAttribsPorts[attin];
                }

                o.addPort = addPort;
                o.longPort = lp;
                o.title = title;
                o.greyout = grey;
                o.group = this.name;

                this.ports[i].setUiAttribs(o);
            }
        };

        this.removeInvalidPorts = () =>
        {
            for (let i = 0; i < this.ports.length; i++)
            {
                if (!this.ports[i]) this.ports.splice(i, 1);
            }

            if (!this.uiAttribs.multiPortManual)
            {
                if (this.ports.length > MIN_NUM_PORTS)

                    for (let i = this.ports.length - 1; i > 1; i--)
                    {
                        if (!this.ports[i].isLinked()) this.uiAttribs.multiPortNum = i;
                        else break;
                    }
            }

            updateArray();
        };

        this.countPorts = () =>
        {
            if (CABLES.UI && !gui.isRemoteClient && gui.patchView && gui.patchView.patchRenderer && gui.patchView.patchRenderer.isDraggingPort())
            {
                clearTimeout(this.retryTo);
                this.retryTo = setTimeout(this.countPorts.bind(this));
                return;
            }
            this.retryTo = null;

            let redo = false;
            this.removeListeners();
            this.removeInvalidPorts();

            for (let i = 0; i < this.ports.length; i++)
            {
                if (this.ports[i] && this.ports[i].links.length > 1)
                {
                    const po = this.ports[i + 1];
                    const otherPort = this.ports[i].links[0].getOtherPort(this.ports[i]);

                    if (!po || !otherPort)
                    {
                        this._log.warn("no port found?");
                    }
                    else
                    {
                        this.ports[i].links[0].remove();
                        this.op.patch.link(this.op, po.name, otherPort.op, otherPort.name);
                        redo = true;
                    }
                    break;
                }
            }

            if (!this.uiAttribs.multiPortManual)
            {
                let foundHole = true;
                while (foundHole)
                {
                    // console.log("search holes...");
                    foundHole = false;

                    for (let i = this.ports.length - 1; i > 1; i--)
                    {
                        if (this.ports[i] && this.ports[i].links.length > 0 && this.ports[i - 1].links.length == 0)
                        {
                            // console.log("found hole!");

                            // found hole
                            const otherPort = this.ports[i].links[0].getOtherPort(this.ports[i]);
                            this.ports[i].links[0].remove();

                            const po = this.ports[i - 1];

                            if (po && this.ports[i])
                            {
                                // console.log("move ", this.ports[i].name, "to", po.name);
                                this.op.patch.link(this.op, po.name, otherPort.op, otherPort.name);
                                foundHole = true;
                                redo = true;
                                break;
                            }
                        }
                    }


                    // this.checkNum();
                }

                // this.removeInvalidPorts();
            }


            if (!this.uiAttribs.multiPortManual) // if auto
            {
                while (this.ports.length > MIN_NUM_PORTS && !this.ports[this.ports.length - 1].isLinked() && !this.ports[this.ports.length - 2].isLinked())
                {
                    let i = this.ports.length - 1;
                    if (!this.ports[i].isLinked() && this.ports[i - 1] && !this.ports[i - 1].isLinked())
                    {
                        this.ports[i].setUiAttribs({ "removed": true });
                        this.ports[i].remove();
                        // this.ports[i] = null;
                        this.ports.splice(i, 1);
                    }
                }
            }

            this.removeInvalidPorts();

            if (!this.uiAttribs.multiPortManual && this.ports.length > 0 && this.ports[this.ports.length - 1].isLinked()) this.newPort();

            updateArray();
            updateUi();

            if (redo) this.countPorts();
            else this.addListeners();
        };

        this.removeListeners = () =>
        {
            for (let i = 0; i < this.ports.length; i++)
            {
                const po = this.ports[i];
                po.multiPortChangeListener = po.off(po.multiPortChangeListener);
                po.multiLinkChangeListener = po.off(po.multiLinkChangeListener);
            }
        };

        this.addListeners = () =>
        {
            for (let i = 0; i < this.ports.length; i++)
            {
                const po = this.ports[i];
                const idx = i;

                if (po.multiPortChangeListener)po.multiPortChangeListener = po.off(po.multiPortChangeListener);
                po.multiPortChangeListener = po.on("change", updateArray.bind(this));


                if (po.multiPortTriggerListener)po.multiPortTriggerListener = po.off(po.multiPortTriggerListener);
                po.multiPortTriggerListener = po.on("trigger", () => { this._onTriggered(idx); });


                // if (po.multiPortTriggerListener)po.multiPortTriggerListener = po.off(po.multiPortTriggerListener);
                // po.multiPortTriggerListener = po.on("trigger", this.trigger());

                if (po.multiLinkChangeListener)po.multiLinkChangeListener = po.off(po.multiLinkChangeListener);
                po.multiLinkChangeListener = po.on("onLinkChanged", () =>
                {
                    this.countPorts();
                    this.emitEvent("onLinkChanged");
                });

                if (po.multiLinkRemoveListener)po.multiLinkRemoveListener = po.off(po.multiLinkRemoveListener);
                po.multiLinkRemoveListener = po.on("onLinkRemoved", () =>
                {
                    // this.removeInvalidPorts();
                    // this.checkNum();
                    // this.countPorts();
                    updateUi();
                    this.emitEvent("onLinkChanged");
                    // this.countPorts.bind(this);
                });
            }
        };

        this.newPort = () =>
        {
            const attrs = {};
            // if (type == CABLES.OP_PORT_TYPE_STRING) attrs.type = "string";
            attrs.type = type;
            const po = new Port(this.op, name + "_" + this.ports.length, type, attrs);

            po.direction = dir;
            this.ports.push(po);
            // console.log("CONSTANTS.PORT_DIR_OUT", CONSTANTS.PORT.PORT_DIR_OUT, this.direction);
            if (this.direction == CONSTANTS.PORT.PORT_DIR_OUT) this.op.addOutPort(po);
            else this.op.addInPort(po);

            if (type == CONSTANTS.OP.OP_PORT_TYPE_NUMBER) po.setInitialValue(0);
            else if (type == CONSTANTS.OP.OP_PORT_TYPE_STRING) po.setInitialValue("");

            this.addListeners();

            updateUi();
            updateArray();
            this.emitEvent("onLinkChanged");
            // console.log("this.op.preservedPortTitles", this.op.preservedPortTitles, this.op.preservedPortTitles[po.name], po.name);
            if (this.op.preservedPortTitles && this.op.preservedPortTitles[po.name]) po.setUiAttribs({ "title": this.op.preservedPortTitles[po.name] });

            return po;
        };

        this.initPorts = () =>
        {
            for (let i = 0; i < MIN_NUM_PORTS; i++) this.newPort();
            updateArray();
            updateUi();
        };

        this.checkNum = () =>
        {
            this.uiAttribs.multiPortNum = Math.max(MIN_NUM_PORTS, this.uiAttribs.multiPortNum);

            while (this.ports.length < this.uiAttribs.multiPortNum) this.newPort();
            while (this.ports.length > this.uiAttribs.multiPortNum) if (this.ports[this.ports.length - 1]) this.ports.pop().remove();

            this.removeInvalidPorts();
        };

        this.incDec = (incDir) =>
        {
            this.uiAttribs.multiPortNum = this.uiAttribs.multiPortNum || MIN_NUM_PORTS;
            // console.log("this.uiAttribs.multiPortNum", this.uiAttribs.multiPortNum, this.uiAttribs.multiPortNum + incDir);
            this.setUiAttribs({ "multiPortNum": this.uiAttribs.multiPortNum + incDir });
            this.checkNum();

            updateUi();
        };

        this.toggleManual = () =>
        {
            this.setUiAttribs({ "multiPortManual": !this.uiAttribs.multiPortManual });
            this.op.refreshParams();
        };

        this.on("onUiAttrChange", (attribs) =>
        {
            if (attribs.hasOwnProperty("multiPortManual"))
            {
                updateUi();
                this.removeInvalidPorts();
                this.checkNum();
                this.countPorts();
                updateUi();
            }
        });


        this.on("onUiAttrChange", this.checkNum.bind(this));
        this.checkNum();
        this.countPorts();
        this.removeInvalidPorts();
        updateUi();
    }
}





;// CONCATENATED MODULE: ./src/core/core_op.js









/**
 * op the class of all operators
 * @namespace external:CABLES#Op
 * @hideconstructor
 */

/**
 * @type {Object}
 * @name attachments
 * @instance
 * @memberof Op
 * @description access file attachments as String values
 * @example
 * // set shader source to attached files (files are called shader.vert / shader.frag)
 * shader.setSource(attachments.shader_vert,attachments.shader_frag);
 */

const Ops = {};

const Op = function ()
{
    EventTarget.apply(this);

    this._log = new Logger("core_op");
    this.data = {}; // UNUSED, DEPRECATED, only left in for backwards compatibility with userops
    this.storage = {}; // op-specific data to be included in export
    this.__objName = "";
    this.portsOut = [];
    this.portsIn = [];
    this.portsInData = []; // original loaded patch data
    this.opId = ""; // unique op id
    this.uiAttribs = {};
    this.enabled = true;
    this.patch = arguments[0];
    this._name = arguments[1];
    this.preservedPortTitles = {};
    this.preservedPortValues = {};
    this.preservedPortLinks = {};

    this._linkTimeRules = {
        "needsLinkedToWork": [],
        "needsParentOp": null
    };

    this.shouldWork = {};
    this.hasUiErrors = false;
    this._uiErrors = {};
    this._hasAnimPort = false;

    if (arguments[1])
    {
        this._shortOpName = CABLES.getShortOpName(arguments[1]);
        this.getTitle();
    }

    this.id = arguments[2] || shortId(); // instance id
    this.onAddPort = null;
    this.onCreate = null;
    this.onResize = null;
    this.onLoaded = null;
    this.onDelete = null;
    this.onError = null;

    this._instances = null;

    /**
     * overwrite this to prerender shader and meshes / will be called by op `loadingStatus`
     * @function preRender
     * @memberof Op
     * @instance
     */
    this.preRender = null;

    /**
     * overwrite this to initialize your op
     * @function init
     * @memberof Op
     * @instance
     */
    this.init = null;

    Object.defineProperty(this, "name", {
        get() { return this.getTitle(); },
        set(v)
        {
            this.setTitle(v);
        }
    });

    Object.defineProperty(this, "_objName", { set(on)
    {
        this.__objName = on; this._log = new Logger("op " + on);
    } });

    Object.defineProperty(this, "objName", { get() { return this.__objName; } });
    Object.defineProperty(this, "shortName", { get() { return this._shortOpName; } });

    if (this.initUi) this.initUi();
};

{
    Op.prototype.clearUiAttrib = function (name)
    {
        const obj = {};
        // obj.name = null;
        this.uiAttrib(obj);
    };

    Op.prototype.require = function (name)
    {
        if (CABLES.platform && CABLES.StandaloneElectron && !CABLES.platform.frontendOptions.isStandalone)
            this.setUiError("notstandalone", "This op will only work in cables standalone version", 3);

        return null;
    };


    Op.prototype.checkMainloopExists = function ()
    {
        if (!CABLES.UI) return;
        if (!this.patch.tempData.mainloopOp) this.setUiError("nomainloop", "patch should have a mainloop to use this op");
        else this.setUiError("nomainloop", null);
    };

    Op.prototype.getTitle = function ()
    {
        if (!this.uiAttribs) return "nouiattribs" + this._name;

        // if ((this.uiAttribs.title === undefined || this.uiAttribs.title === "") && this.objName.indexOf("Ops.Ui.") == -1)
        //     this.uiAttribs.title = this._shortOpName;

        return this.uiAttribs.title || this._shortOpName;
    };

    Op.prototype.setTitle = function (title)
    {
        // this._log.log("settitle", title);
        // this._log.log(
        //     (new Error()).stack
        // );

        if (title != this.getTitle()) this.uiAttr({ "title": title });
    };

    Op.prototype.setStorage = function (newAttribs)
    {
        if (!newAttribs) return;
        this.storage = this.storage || {};

        let changed = false;
        for (const p in newAttribs)
        {
            if (this.storage[p] != newAttribs[p]) changed = true;
            this.storage[p] = newAttribs[p];
        }

        if (changed) this.emitEvent("onStorageChange", newAttribs);
    };

    Op.prototype.isSubPatchOp = function ()
    {
        if (this.patchId && this.storage) return (this.storage.subPatchVer || this.storage.blueprintVer || 0);
        return false;
    };

    const _setUiAttrib = function (newAttribs)
    {
        if (!newAttribs) return;

        if (newAttribs.error || newAttribs.warning || newAttribs.hint)
        {
            this._log.warn("old ui error/warning attribute in " + this._name + ", use op.setUiError !", newAttribs);
        }


        if (typeof newAttribs != "object") this._log.error("op.uiAttrib attribs are not of type object");
        if (!this.uiAttribs) this.uiAttribs = {};

        let changed = false;
        let emitMove = false;
        if (
            CABLES.UI &&
            newAttribs.hasOwnProperty("translate") &&
            (
                !this.uiAttribs.translate ||
                this.uiAttribs.translate.x != newAttribs.translate.x ||
                this.uiAttribs.translate.y != newAttribs.translate.y
            )) emitMove = true;


        if (newAttribs.hasOwnProperty("title") && newAttribs.title != this.uiAttribs.title)
        {
            // const doEmitEvent = newAttribs.title != this.getTitle();
            this.uiAttribs.title = newAttribs.title;
            // if (doEmitEvent) this.emitEvent("onTitleChange", newAttribs.title);
            changed = true;
            // this.setTitle(newAttribs.title);
        }

        if (newAttribs.hasOwnProperty("disabled")) this.setEnabled(!newAttribs.disabled);

        for (const p in newAttribs)
        {
            if (this.uiAttribs[p] != newAttribs[p]) changed = true;
            this.uiAttribs[p] = newAttribs[p];
        }


        if (this.uiAttribs.hasOwnProperty("selected") && this.uiAttribs.selected == false) delete this.uiAttribs.selected;


        if (changed)
        {
            this.emitEvent("onUiAttribsChange", newAttribs);
            this.patch.emitEvent("onUiAttribsChange", this, newAttribs);
        }


        if (emitMove) this.emitEvent("move");
    };
    /**
     * setUiAttrib
     * possible values:
     * <pre>
     * warning - warning message - showing up in op parameter panel
     * error - error message - showing up in op parameter panel
     * extendTitle - op title extension, e.g. [ + ]
     * </pre>
     * @function setUiAttrib
     * @param {Object} newAttribs, e.g. {"attrib":value}
     * @memberof Op
     * @instance
     * @example
     * op.setUiAttrib({"extendTitle":str});
     */
    Op.prototype.setUiAttribs = Op.prototype.setUiAttrib = Op.prototype.uiAttr = _setUiAttrib;

    Op.prototype.getName = function ()
    {
        if (this.uiAttribs.name) return this.uiAttribs.name;
        return this._name;
    };

    Op.prototype.addOutPort = function (p)
    {
        p.direction = CONSTANTS.PORT.PORT_DIR_OUT;
        p._op = this;
        this.portsOut.push(p);
        this.emitEvent("onPortAdd", p);
        return p;
    };

    Op.prototype.hasDynamicPort = function ()
    {
        let i = 0;
        for (i = 0; i < this.portsIn.length; i++)
        {
            if (this.portsIn[i].type == CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC) return true;
            if (this.portsIn[i].getName() == "dyn") return true;
        }
        for (i = 0; i < this.portsOut.length; i++)
        {
            if (this.portsOut[i].type == CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC) return true;
            if (this.portsOut[i].getName() == "dyn") return true;
        }

        return false;
    };

    Op.prototype.addInPort = function (p)
    {
        if (!(p instanceof Port)) throw new Error("parameter is not a port!");

        p.direction = CONSTANTS.PORT.PORT_DIR_IN;
        p._op = this;

        this.portsIn.push(p);
        this.emitEvent("onPortAdd", p);

        return p;
    };

    /**
     * create a trigger input port
     * @function inTrigger
     * @instance
     * @memberof Op
     * @param {String} name
     * @return {Port} created port
     *
     */
    Op.prototype.inFunction = Op.prototype.inTrigger = function (name, v)
    {
        const p = this.addInPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_FUNCTION));
        if (v !== undefined) p.set(v);
        return p;
    };

    /**
     * create multiple UI trigger buttons
     * @function inTriggerButton
     * @memberof Op
     * @instance
     * @param {String} name
     * @param {Array} names
     * @return {Port} created port
     */
    Op.prototype.inFunctionButton = Op.prototype.inTriggerButton = function (name, v)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_FUNCTION, {
                "display": "button"
            })
        );
        if (v !== undefined) p.set(v);
        return p;
    };

    Op.prototype.inFunctionButton = Op.prototype.inUiTriggerButtons = function (name, v)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_FUNCTION, {
                "display": "buttons"
            })
        );
        if (v !== undefined) p.set(v);
        return p;
    };



    /**
     * create a number value input port
     * @function inFloat
     * @memberof Op
     * @instance
     * @param {String} name
     * @param {Number} value
     * @return {Port} created port
     */
    Op.prototype.inValueFloat = Op.prototype.inValue = Op.prototype.inFloat = function (name, v)
    {
        const p = this.addInPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE));

        p.setInitialValue(v);

        return p;
    };

    /**
     * create a boolean input port, displayed as a checkbox
     * @function inBool
     * @instance
     * @memberof Op
     * @param {String} name
     * @param {Boolean} value
     * @return {Port} created port
     */
    Op.prototype.inValueBool = Op.prototype.inBool = function (name, v)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_NUMBER, {
                "display": "bool"
            })
        );

        if (v === true)v = 1;
        if (v === false)v = 0;
        p.setInitialValue(v);

        return p;
    };


    Op.prototype.inMultiPort = function (name, type)
    {
        const p = new MultiPort(
            this,
            name,
            type,
            CONSTANTS.PORT.PORT_DIR_IN,
            {
                "addPort": true,
                "hidePort": true
            }
        );
        p.ignoreValueSerialize = true;

        this.addInPort(p);
        p.initPorts();

        return p;
    };

    Op.prototype.outMultiPort = function (name, type, uiAttribsPort = {})
    {
        const p = new MultiPort(
            this,
            name,
            type,
            CONSTANTS.PORT.PORT_DIR_OUT,
            {
                "display": "multiport",
                "hidePort": true
            },
            uiAttribsPort
        );
        p.ignoreValueSerialize = true;

        this.addOutPort(p);
        p.initPorts();

        return p;
    };



    Op.prototype.inValueString = function (name, v)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, {
                "type": "string"
            })
        );
        p.value = "";

        p.setInitialValue(v);
        return p;
    };

    /**
     * create a String value input port
     * @function inString
     * @instance
     * @memberof Op
     * @param {String} name
     * @param {String} value default value
     * @return {Port} created port
     */
    Op.prototype.inString = function (name, v)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_STRING, {
                "type": "string"
            })
        );
        v = v || "";
        // p.value = v;

        p.setInitialValue(v);
        return p;
    };

    /**
     * create a String value input port displayed as TextArea
     * @function inValueText
     * @instance
     * @memberof Op
     * @param {String} name
     * @param {String} value default value
     * @return {Port} created port
     */
    Op.prototype.inValueText = function (name, v)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, {
                "type": "string",
                "display": "text"
            })
        );
        p.value = "";

        p.setInitialValue(v);
        // if (v !== undefined)
        // {
        //     p.set(v);
        //     p.defaultValue = v;
        // }
        return p;
    };

    Op.prototype.inTextarea = function (name, v)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_STRING, {
                "type": "string",
                "display": "text"
            })
        );
        p.value = "";
        if (v !== undefined)
        {
            p.set(v);
            p.defaultValue = v;
        }
        return p;
    };

    /**
     * create a String value input port displayed as editor
     * @function inStringEditor
     * @instance
     * @memberof Op
     * @param {String} name
     * @param {String} value default value
     * @return {Port} created port
     */
    // new string
    Op.prototype.inStringEditor = function (name, v, syntax, hideFormatButton = true)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_STRING, {
                "type": "string",
                "display": "editor",
                "editShortcut": true,
                "editorSyntax": syntax,
                "hideFormatButton": hideFormatButton
            }));

        p.value = "";
        if (v !== undefined)
        {
            p.set(v);
            p.defaultValue = v;
        }
        return p;
    };

    // old
    Op.prototype.inValueEditor = function (name, v, syntax, hideFormatButton = true)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_NUMBER, {
                "type": "string",
                "display": "editor",
                "editorSyntax": syntax,
                "hideFormatButton": hideFormatButton
            })
        );
        p.value = "";
        if (v !== undefined)
        {
            p.set(v);
            p.defaultValue = v;
        }
        return p;
    };

    /**
     * create a string select box
     * @function inDropDown
     * @instance
     * @memberof Op
     * @param {String} name
     * @param {Array} values
     * @param {String} value default value
     * @return {Port} created port
     */
    Op.prototype.inValueSelect = Op.prototype.inDropDown = function (name, values, v, noindex)
    {
        let p = null;
        if (!noindex)
        {
            const indexPort = new Port(this, name + " index", CONSTANTS.OP.OP_PORT_TYPE_NUMBER, {
                "increment": "integer",
                "hideParam": true
            });
            const n = this.addInPort(indexPort);

            if (values) for (let i = 0; i < values.length; i++) values[i] = String(values[i]);

            const valuePort = new ValueSelectPort(
                this,
                name,
                CONSTANTS.OP.OP_PORT_TYPE_NUMBER,
                {
                    "display": "dropdown",
                    "hidePort": true,
                    "type": "string",
                    "values": values
                },
                n
            );

            valuePort.indexPort = indexPort;

            valuePort.on("change", (val, thePort) =>
            {
                if (!thePort.indexPort.isLinked() && thePort.uiAttribs.values)
                {
                    const idx = thePort.uiAttribs.values.indexOf(val);
                    if (idx > -1) thePort.indexPort.set(idx);
                }
            });

            indexPort.onLinkChanged = function ()
            {
                valuePort.setUiAttribs({ "greyout": indexPort.isLinked() });
            };

            p = this.addInPort(valuePort);

            if (v !== undefined)
            {
                p.set(v);
                const index = values.findIndex((item) => { return item == v; });
                n.setValue(index);
                p.defaultValue = v;
                n.defaultValue = index;
            }
        }
        else
        {
            const valuePort = new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, {
                "display": "dropdown",
                "hidePort": true,
                "type": "string",
                values
            });

            p = this.addInPort(valuePort);
        }

        return p;
    };

    /**
     * create a string switch box
     * @function inSwitch
     * @instance
     * @memberof Op
     * @param {String} name
     * @param {Array} values
     * @param {String} value default value
     * @return {Port} created port
     */
    Op.prototype.inSwitch = function (name, values, v, noindex)
    {
        let p = null;
        if (!noindex)
        {
            if (!v)v = values[0];
            const indexPort = new Port(this, name + " index", CONSTANTS.OP.OP_PORT_TYPE_VALUE, {
                "increment": "integer",
                "values": values,
                "hideParam": true
            });
            const n = this.addInPort(indexPort);

            if (values) for (let i = 0; i < values.length; i++) values[i] = String(values[i]);

            const switchPort = new SwitchPort(
                this,
                name,
                CONSTANTS.OP.OP_PORT_TYPE_STRING,
                {
                    "display": "switch",
                    "hidePort": true,
                    "type": "string",
                    "values": values
                },
                n
            );

            switchPort.indexPort = indexPort;

            switchPort.on("change", (val, thePort) =>
            {
                if (!thePort.indexPort.isLinked() && thePort.uiAttribs.values)
                {
                    const idx = thePort.uiAttribs.values.indexOf(val);
                    if (idx > -1) thePort.indexPort.set(idx);
                }
            });

            indexPort.onLinkChanged = function ()
            {
                switchPort.setUiAttribs({ "greyout": indexPort.isLinked() });
            };
            p = this.addInPort(switchPort);

            if (v !== undefined)
            {
                p.set(v);
                const index = values.findIndex((item) => { return item == v; });
                n.setValue(index);
                p.defaultValue = v;
                n.defaultValue = index;
            }
        }
        else
        {
            const switchPort = new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_STRING, {
                "display": "switch",
                "hidePort": true,
                "type": "string",
                "values": values
            });
            p = this.addInPort(switchPort);
        }

        return p;
    };

    /**
     * create a integer input port
     * @function inInt
     * @instance
     * @memberof Op
     * @param {String} name
     * @param {number} value default value
     * @return {Port} created port
     */
    Op.prototype.inValueInt = Op.prototype.inInt = function (name, v)
    {
        // old
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, {
                "increment": "integer"
            })
        );
        if (v !== undefined)
        {
            p.set(v);
            p.defaultValue = v;
        }
        return p;
    };

    /**
     * create a file/URL input port
     * @function inURL
     * @instance
     * @memberof Op
     * @param {String} name
     * @return {Port} created port
     */
    Op.prototype.inFile = function (name, filter, v)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, {
                "display": "file",
                "type": "string",
                "filter": filter
            })
        );
        if (v !== undefined)
        {
            p.set(v);
            p.defaultValue = v;
        }
        return p;
    };

    Op.prototype.inUrl = function (name, filter, v)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_STRING, {
                "display": "file",
                "type": "string",
                "filter": filter
            })
        );
        if (v !== undefined)
        {
            p.set(v);
            p.defaultValue = v;
        }
        return p;
    };

    /**
     * create a texture input port
     * @function inTexture
     * @instance
     * @memberof Op
     * @param {String} name
     * @return {Port} created port
     */
    Op.prototype.inTexture = function (name, v)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_OBJECT, {
                "display": "texture",
                "objType": "texture",
                "preview": true
            })
        );
        p.ignoreValueSerialize = true;
        if (v !== undefined) p.set(v);
        return p;
    };


    /**
     * create a object input port
     * @function inObject
     * @instance
     * @memberof Op
     * @param {String} name
     * @return {Port} created port
     */
    Op.prototype.inObject = function (name, v, objType)
    {
        const p = this.addInPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_OBJECT, { "objType": objType }));
        p.ignoreValueSerialize = true;

        if (v !== undefined) p.set(v);
        return p;
    };

    Op.prototype.inGradient = function (name, v)
    {
        const p = this.addInPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, {
                "display": "gradient"
                // "hidePort": true
            })
        );
        if (v !== undefined) p.set(v);
        return p;
    };


    Op.prototype.getPortVisibleIndex = function (p)
    {
        let ports = this.portsIn;
        if (p.direction == CONSTANTS.PORT_DIR_OUT)ports = this.portsOut;

        let index = 0;
        for (let i = 0; i < ports.length; i++)
        {
            if (ports[i].uiAttribs.hidePort) continue;
            index++;
            if (ports[i] == p) return index;
        }
    };

    /**
     * create a array input port
     * @function inArray
     * @instance
     * @memberof Op
     * @param {String} name
     * @return {Port} created port
     */
    Op.prototype.inArray = function (name, v, stride)
    {
        if (!stride && CABLES.UTILS.isNumeric(v))stride = v;

        const p = this.addInPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_ARRAY, { "stride": stride }));

        if (v !== undefined && (Array.isArray(v) || v == null)) p.set(v);

        // if (v !== undefined) p.set(v);
        return p;
    };

    /**
     * create a value slider input port
     * @function inFloatSlider
     * @instance
     * @memberof Op
     * @param {String} name
     * @param {number} defaultvalue
     * @param {number} min
     * @param {number} max
     * @return {Port} created port
     */
    Op.prototype.inValueSlider = Op.prototype.inFloatSlider = function (name, v, min, max)
    {
        const uiattribs = { "display": "range" };

        if (min != undefined && max != undefined)
        {
            uiattribs.min = min;
            uiattribs.max = max;
        }

        const p = this.addInPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, uiattribs));
        if (v !== undefined)
        {
            p.set(v);
            p.defaultValue = v;
        }
        return p;
    };

    /**
     * create output trigger port
     * @function outTrigger
     * @instance
     * @memberof Op
     * @param {String} name
     * @return {Port} created port
     */
    Op.prototype.outFunction = Op.prototype.outTrigger = function (name, v)
    {
        // old
        const p = this.addOutPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_FUNCTION));
        if (v !== undefined) p.set(v);
        return p;
    };

    /**
     * create output value port
     * @function outNumber
     * @instance
     * @memberof Op
     * @param {String} name
     * @param {number} default value
     * @return {Port} created port
     */
    Op.prototype.outValue = Op.prototype.outNumber = function (name, v)
    {
        // old
        const p = this.addOutPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE));
        if (v !== undefined) p.set(v);
        return p;
    };

    /**
     * deprecated create output boolean port
     * @deprecated
     * @function outBool
     * @instance
     * @memberof Op
     * @param {String} name
     * @return {Port} created port
     */
    Op.prototype.outValueBool = Op.prototype.outBool = function (name, v)
    {
        // old: use outBoolNum
        const p = this.addOutPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, {
                "display": "bool"
            })
        );
        if (v !== undefined) p.set(v);
        else p.set(0);
        return p;
    };

    /**
     * create output boolean port,value will be converted to 0 or 1
     * @function outBoolNum
     * @instance
     * @memberof Op
     * @param {String} name
     * @return {Port} created port
     */
    Op.prototype.outBoolNum = function (name, v)
    {
        const p = this.addOutPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, {
                "display": "boolnum"
            })
        );

        p.set = function (b)
        {
            this.setValue(b ? 1 : 0);
            // this._log.log("bool set", b, this.get());
        }.bind(p);

        if (v !== undefined) p.set(v);
        else p.set(0);
        return p;
    };

    /**
     * create output string port
     * @function outString
     * @instance
     * @memberof Op
     * @param {String} name
     * @return {Port} created port
     */
    Op.prototype.outValueString = function (name, v)
    {
        const p = this.addOutPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_VALUE, {
                "type": "string"
            })
        );
        if (v !== undefined) p.set(v);
        return p;
    };
    Op.prototype.outString = function (name, v)
    {
        const p = this.addOutPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_STRING, {
                "type": "string"
            })
        );
        if (v !== undefined) p.set(v);
        else p.set("");
        return p;
    };

    /**
     * create output object port
     * @function outObject
     * @instance
     * @memberof Op
     * @param {String} name
     * @return {Port} created port
     */
    Op.prototype.outObject = function (name, v, objType)
    {
        const p = this.addOutPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_OBJECT, { "objType": objType || null }));
        p.set(v || null);
        p.ignoreValueSerialize = true;
        return p;
    };

    /**
     * create output array port
     * @function outArray
     * @instance
     * @memberof Op
     * @param {String} name
     * @return {Port} created port
     */
    Op.prototype.outArray = function (name, v, stride)
    {
        if (!stride && CABLES.UTILS.isNumeric(v))stride = v;
        const p = this.addOutPort(new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_ARRAY, { "stride": stride }));
        if (v !== undefined && (Array.isArray(v) || v == null)) p.set(v);

        p.ignoreValueSerialize = true;
        return p;
    };

    /**
     * create output texture port
     * @function outTexture
     * @instance
     * @memberof Op
     * @param {String} name
     * @return {Port} created port
     */
    Op.prototype.outTexture = function (name, v)
    {
        const p = this.addOutPort(
            new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_OBJECT, {
                "preview": true,
                "objType": "texture",
                "display": "texture"
            })
        );
        if (v !== undefined) p.setRef(v || CGL.Texture.getEmptyTexture(this.patch.cgl));

        p.ignoreValueSerialize = true;
        return p;
    };

    Op.prototype.inDynamic = function (name, filter, options, v)
    {
        const p = new Port(this, name, CONSTANTS.OP.OP_PORT_TYPE_DYNAMIC, options);

        p.shouldLink = function (p1, p2)
        {
            if (filter && UTILS.isArray(filter))
            {
                for (let i = 0; i < filter.length; i++)
                {
                    if (p1 == this && p2.type === filter[i]) return true;
                    if (p2 == this && p1.type === filter[i]) return true;
                }
                return false; // types do not match
            }
            return true; // no filter set
        };

        this.addInPort(p);
        if (v !== undefined)
        {
            p.set(v);
            p.defaultValue = v;
        }
        return p;
    };

    Op.prototype.removeLinks = function ()
    {
        for (let i = 0; i < this.portsIn.length; i++) this.portsIn[i].removeLinks();
        for (let i = 0; i < this.portsOut.length; i++) this.portsOut[i].removeLinks();
    };

    Op.prototype.getSerialized = function ()
    {
        const opObj = {};

        if (this.opId) opObj.opId = this.opId;
        if (this.patch.storeObjNames) opObj.objName = this.objName;

        opObj.id = this.id;
        opObj.uiAttribs = JSON.parse(JSON.stringify(this.uiAttribs)) || {};

        if (this.storage && Object.keys(this.storage).length > 0) opObj.storage = JSON.parse(JSON.stringify(this.storage));
        if (this.uiAttribs.hasOwnProperty("working") && this.uiAttribs.working == true) delete this.uiAttribs.working;
        if (opObj.uiAttribs.hasOwnProperty("uierrors")) delete opObj.uiAttribs.uierrors;

        if (opObj.uiAttribs.title === "") delete opObj.uiAttribs.title;
        if (opObj.uiAttribs.color === null) delete opObj.uiAttribs.color;
        if (opObj.uiAttribs.comment === null) delete opObj.uiAttribs.comment;

        if (opObj.uiAttribs.title == this._shortOpName ||
            (this.uiAttribs.title || "").toLowerCase() == this._shortOpName.toLowerCase()) delete opObj.uiAttribs.title;

        opObj.portsIn = [];
        opObj.portsOut = [];

        for (let i = 0; i < this.portsIn.length; i++)
        {
            const s = this.portsIn[i].getSerialized();
            if (s) opObj.portsIn.push(s);
        }

        for (let i = 0; i < this.portsOut.length; i++)
        {
            const s = this.portsOut[i].getSerialized();
            if (s) opObj.portsOut.push(s);
        }

        if (opObj.portsIn.length == 0) delete opObj.portsIn;
        if (opObj.portsOut.length == 0) delete opObj.portsOut;
        cleanJson(opObj);

        return opObj;
    };

    Op.prototype.getFirstOutPortByType = function (type)
    {
        for (const ipo in this.portsOut) if (this.portsOut[ipo].type == type) return this.portsOut[ipo];
    };

    Op.prototype.getFirstInPortByType = function (type)
    {
        for (const ipo in this.portsIn) if (this.portsIn[ipo].type == type) return this.portsIn[ipo];
    };

    /**
     * return port by the name portName
     * @function getPort
     * @instance
     * @memberof Op
     * @param {String} portName
     * @return {Port}
     */
    Op.prototype.getPort = Op.prototype.getPortByName = function (name, lowerCase)
    {
        if (lowerCase)
        {
            for (let ipi = 0; ipi < this.portsIn.length; ipi++)
                if (this.portsIn[ipi].getName().toLowerCase() == name || this.portsIn[ipi].id.toLowerCase() == name)
                    return this.portsIn[ipi];

            for (let ipo = 0; ipo < this.portsOut.length; ipo++)
                if (this.portsOut[ipo].getName().toLowerCase() == name || this.portsOut[ipo].id.toLowerCase() == name)
                    return this.portsOut[ipo];
        }
        else
        {
            for (let ipi = 0; ipi < this.portsIn.length; ipi++)
                if (this.portsIn[ipi].getName() == name || this.portsIn[ipi].id == name)
                    return this.portsIn[ipi];

            for (let ipo = 0; ipo < this.portsOut.length; ipo++)
                if (this.portsOut[ipo].getName() == name || this.portsOut[ipo].id == name)
                    return this.portsOut[ipo];
        }
    };


    /**
     * return port by the name id
     * @function getPortById
     * @instance
     * @memberof Op
     * @param {String} id
     * @return {Port}
     */
    Op.prototype.getPortById = function (id)
    {
        for (let ipi = 0; ipi < this.portsIn.length; ipi++) if (this.portsIn[ipi].id == id) return this.portsIn[ipi];
        for (let ipo = 0; ipo < this.portsOut.length; ipo++) if (this.portsOut[ipo].id == id) return this.portsOut[ipo];
    };

    Op.prototype.updateAnims = function ()
    {
        if (this._hasAnimPort)
            for (let i = 0; i < this.portsIn.length; i++) this.portsIn[i].updateAnim();
    };

    Op.prototype.log = function ()
    {
        this._log.log(...arguments);
    };

    Op.prototype.error = Op.prototype.logError = function ()
    {
        // if (!this)
        // {
        //     this._log.error("no this...!!!");
        //     debugger;
        //     return;
        // }
        // const initiator = "op " + this.objName;
        // if (CABLES.UI && !CABLES.UI.logFilter.filterLog({ "initiator": initiator, "opInstId": this.id, "level": 2 }, ...arguments)) return;

        // // if (this.patch.silent) return;
        // const args = ["[op " + CABLES.getShortOpName(this.objName) + "]"];
        // args.push.apply(args, arguments);
        // Function.prototype.apply.apply(this._log.error, [console, args]);// eslint-disable-line
        // if (window.gui) window.gui.emitEvent("opLogEvent", this.objName, "error", arguments);
        this._log.error(...arguments);
    };

    Op.prototype.warn = Op.prototype.logWarn = function ()
    {
        this._log.warn(...arguments);

        // const initiator = "op " + this.objName;
        // if (CABLES.UI && !CABLES.UI.logFilter.filterLog({ "initiator": initiator, "opInstId": this.id, "level": 1 }, ...arguments)) return;

        // // if (this.patch.silent) return;
        // const args = ["[op " + CABLES.getShortOpName(this.objName) + "]"];
        // args.push.apply(args, arguments);
        // Function.prototype.apply.apply(this._log.warn, [console, args]);// eslint-disable-line
    };

    Op.prototype.verbose = Op.prototype.logVerbose = function ()
    {
        // const initiator = "op " + CABLES.getShortOpName(this.objName);
        // if (CABLES.UI && !CABLES.UI.logFilter.filterLog({ "initiator": initiator, "opInstId": this.id, "level": 0 }, ...arguments)) return;

        // if (!CABLES.UI && this.patch.silent) return;

        // const args = ["[" + initiator + "]"];
        // args.push.apply(args, arguments);
        // Function.prototype.apply.apply(this._log.info, [console, args]);// eslint-disable-line
        this._log.verbose(...arguments);
    };


    Op.prototype.profile = function (enable)
    {
        for (let ipi = 0; ipi < this.portsIn.length; ipi++)
        {
            this.portsIn[ipi]._onTriggered = this.portsIn[ipi]._onTriggeredProfiling;
            this.portsIn[ipi].set = this.portsIn[ipi]._onSetProfiling;
        }
    };

    Op.prototype.findParent = function (objName)
    {
        for (let ipi = 0; ipi < this.portsIn.length; ipi++)
        {
            if (this.portsIn[ipi].isLinked())
            {
                if (this.portsIn[ipi].links[0].portOut.parent.objName == objName)
                    return this.portsIn[ipi].links[0].portOut.parent;

                let found = null;
                found = this.portsIn[ipi].links[0].portOut.parent.findParent(objName);
                if (found) return found;
            }
        }
        return null;
    };


    // todo: check instancing stuff?
    Op.prototype.cleanUp = function ()
    {
        if (this._instances)
        {
            for (let i = 0; i < this._instances.length; i++)
            {
                if (this._instances[i].onDelete) this._instances[i].onDelete();
            }


            this._instances.length = 0;
        }
        for (let i = 0; i < this.portsIn.length; i++)
        {
            this.portsIn[i].setAnimated(false);
        }

        if (this.onAnimFrame) this.patch.removeOnAnimFrame(this);
    };

    // todo: check instancing stuff?
    Op.prototype.instanced = function (triggerPort)
    {
        return false;
        // this._log.log("instanced", this.patch.instancing.numCycles());
        // if (this.patch.instancing.numCycles() === 0) return false;


        // let i = 0;
        // let ipi = 0;
        // if (!this._instances || this._instances.length != this.patch.instancing.numCycles())
        // {
        //     if (!this._instances) this._instances = [];
        //     this._.log("creating instances of ", this.objName, this.patch.instancing.numCycles(), this._instances.length);
        //     this._instances.length = this.patch.instancing.numCycles();

        //     for (i = 0; i < this._instances.length; i++)
        //     {
        //         this._instances[i] = this.patch.createOp(this.objName, true);
        //         this._instances[i].instanced = function ()
        //         {
        //             return false;
        //         };
        //         this._instances[i].uiAttr(this.uiAttribs);

        //         for (let ipo = 0; ipo < this.portsOut.length; ipo++)
        //         {
        //             if (this.portsOut[ipo].type == CONSTANTS.OP.OP_PORT_TYPE_FUNCTION)
        //             {
        //                 this._instances[i].getPortByName(this.portsOut[ipo].name).trigger = this.portsOut[ipo].trigger.bind(this.portsOut[ipo]);
        //             }
        //         }
        //     }

        //     for (ipi = 0; ipi < this.portsIn.length; ipi++)
        //     {
        //         this.portsIn[ipi].onChange = null;
        //         this.portsIn[ipi].onValueChanged = null;
        //     }
        // }

        // const theTriggerPort = null;
        // for (ipi = 0; ipi < this.portsIn.length; ipi++)
        // {
        //     if (
        //         this.portsIn[ipi].type == CONSTANTS.OP.OP_PORT_TYPE_VALUE ||
        //         this.portsIn[ipi].type == CONSTANTS.OP.OP_PORT_TYPE_ARRAY
        //     )
        //     {
        //         this._instances[this.patch.instancing.index()].portsIn[ipi].set(this.portsIn[ipi].get());
        //     }
        //     if (this.portsIn[ipi].type == CONSTANTS.OP.OP_PORT_TYPE_FUNCTION)
        //     {
        //         // if(this._instances[ this.patch.instancing.index() ].portsIn[ipi].name==triggerPort.name)
        //         // theTriggerPort=this._instances[ this.patch.instancing.index() ].portsIn[ipi];
        //     }
        // }

        // if (theTriggerPort) theTriggerPort.onTriggered();

        // for (ipi = 0; ipi < this.portsOut.length; ipi++)
        // {
        //     if (this.portsOut[ipi].type == CONSTANTS.OP.OP_PORT_TYPE_VALUE)
        //     {
        //         this.portsOut[ipi].set(this._instances[this.patch.instancing.index()].portsOut[ipi].get());
        //     }
        // }

        // return true;
    };

    // todo: check instancing stuff?
    Op.prototype.initInstancable = function ()
    {
        //         if(this.isInstanced)
        //         {
        //             this._log.log('cancel instancing');
        //             return;
        //         }
        //         this._instances=[];
        //         for(var ipi=0;ipi<this.portsIn.length;ipi++)
        //         {
        //             if(this.portsIn[ipi].type==CONSTANTS.OP.OP_PORT_TYPE_VALUE)
        //             {
        //
        //             }
        //             if(this.portsIn[ipi].type==CONSTANTS.OP.OP_PORT_TYPE_FUNCTION)
        //             {
        //                 // var piIndex=ipi;
        //                 this.portsIn[ipi].onTriggered=function(piIndex)
        //                 {
        //
        //                     var i=0;
        // // this._log.log('trigger',this._instances.length);
        //
        //                 }.bind(this,ipi );
        //
        //             }
        // };
        // this._instances=null;
    };

    Op.prototype.setValues = function (obj)
    {
        for (const i in obj)
        {
            const port = this.getPortByName(i);
            if (port) port.set(obj[i]);
            else this._log.warn("op.setValues: port not found:", i);
        }
    };

    /**
     * return true if op has this error message id
     * @function hasUiError
     * @instance
     * @memberof Op
     * @param {id} error id
     * @returns {Boolean} - has id
     */
    Op.prototype.hasUiError = function (id)
    {
        return this._uiErrors.hasOwnProperty(id) && this._uiErrors[id];
    };

    /**
     * show op error message - set message to null to remove error message
     * @function setUiError
     * @instance
     * @memberof Op
     * @param {id} error id
     * @param {txt} text message
     * @param {level} level
     */
    Op.prototype.setUiError = function (id, txt, level)
    {
        // overwritten in ui: core_extend_op
    };

    // todo: remove
    Op.prototype.setError = function (id, txt)
    {
        this._log.warn("old error message op.error() - use op.setUiError()");
    };


    /**
     * enable/disable op
     * @function
     * @instance
     * @memberof Op
     * @param {boolean}
     */
    Op.prototype.setEnabled = function (b)
    {
        this.enabled = b;
        this.emitEvent("onEnabledChange", b);
    };

    /**
     * organize ports into a group
     * @function
     * @instance
     * @memberof Op
     * @param {String} name
     * @param {Array} ports
     */
    Op.prototype.setPortGroup = function (name, ports)
    {
        for (let i = 0; i < ports.length; i++)
        {
            if (ports[i])
                if (ports[i].setUiAttribs) ports[i].setUiAttribs({ "group": name });
                else
                {
                    this._log.error("setPortGroup: invalid port!");
                }
        }
    };

    /**
     * visually indicate ports that they are coordinate inputs
     * @function
     * @instance
     * @memberof Op
     * @param {Port} portX
     * @param {Port} portY
     * @param {Port} portZ
     */
    Op.prototype.setUiAxisPorts = function (px, py, pz)
    {
        if (px) px.setUiAttribs({ "axis": "X" });
        if (py) py.setUiAttribs({ "axis": "Y" });
        if (pz) pz.setUiAttribs({ "axis": "Z" });
    };

    /**
     * remove port from op
     * @function removePort
     * @instance
     * @memberof Op
     * @param {Port} port to remove
     */
    Op.prototype.removePort = function (port)
    {
        for (let ipi = 0; ipi < this.portsIn.length; ipi++)
        {
            if (this.portsIn[ipi] == port)
            {
                this.portsIn.splice(ipi, 1);
                this.emitEvent("onUiAttribsChange", {});
                this.emitEvent("onPortRemoved", {});
                return;
            }
        }
        for (let ipi = 0; ipi < this.portsOut.length; ipi++)
        {
            if (this.portsOut[ipi] == port)
            {
                this.portsOut.splice(ipi, 1);
                this.emitEvent("onUiAttribsChange", {});
                this.emitEvent("onPortRemoved", {});
                return;
            }
        }
    };

    Op.prototype._checkLinksNeededToWork = function () {};

    /**
     * show a warning of this op is not a child of parentOpName
     * @function
     * @instance
     * @memberof Op
     * @param {String} parentOpName
     */
    Op.prototype.toWorkNeedsParent = function (parentOpName)
    {
        this._linkTimeRules.needsParentOp = parentOpName;
    };

    // /**
    //  * show a warning of this op is a child of parentOpName
    //  * @function
    //  * @instance
    //  * @memberof Op
    //  * @param {String} parentOpName
    //  */
    Op.prototype.toWorkShouldNotBeChild = function (parentOpName, type)
    {
        if (!this.patch.isEditorMode()) return;
        this._linkTimeRules.forbiddenParent = parentOpName;
        if (type != undefined) this._linkTimeRules.forbiddenParentType = type;
    };


    /**
     * show a small X to indicate op is not working when given ports are not linked
     * @function
     * @instance
     * @memberof Op
     * @param {Port} port1
     * @param {Port} port2
     * @param {Port} port3
     */
    Op.prototype.toWorkPortsNeedToBeLinked = function ()
    {
        if (!this.patch.isEditorMode()) return;
        for (let i = 0; i < arguments.length; i++)
            if (this._linkTimeRules.needsLinkedToWork.indexOf(arguments[i]) == -1) this._linkTimeRules.needsLinkedToWork.push(arguments[i]);
    };
    Op.prototype.toWorkPortsNeedToBeLinkedReset = function ()
    {
        if (!this.patch.isEditorMode()) return;
        this._linkTimeRules.needsLinkedToWork.length = 0;
        if (this.checkLinkTimeWarnings) this.checkLinkTimeWarnings();
    };

    Op.prototype.initVarPorts = function ()
    {
        for (let i = 0; i < this.portsIn.length; i++)
        {
            if (this.portsIn[i].getVariableName()) this.portsIn[i].setVariable(this.portsIn[i].getVariableName());
        }
    };

    /**
     * refresh op parameters, if current op is selected
     * @function
     * @instance
     * @memberof Op
     */
    Op.prototype.refreshParams = function ()
    {
        if (this.patch && this.patch.isEditorMode() && this.isCurrentUiOp())
        {
            gui.opParams.show(this);
        }
    };

    /**
     * Returns true if op is selected and parameter are shown in the editor, can only return true if in editor/ui
     * @function isCurrentUiOp
     * @instance
     * @memberof Op
     * @returns {Boolean} - is current ui op
     */
    Op.prototype.isCurrentUiOp = function ()
    {
        if (this.patch.isEditorMode()) return gui.patchView.isCurrentOp(this);
    };

    /**
     * Implement to render 2d canvas based graphics from in an op
     * @function renderVizLayer
     * @instance
     * @memberof Op
     * @param {ctx} context of canvas 2d
     * @param {Object} layer info
     * @param {number} layer.x x position on canvas
     * @param {number} layer.y y position on canvas
     * @param {number} layer.width width of canvas
     * @param {number} layer.height height of canvas
     * @param {number} layer.scale current scaling of patchfield view
     */
    Op.prototype.renderVizLayer = null; // optionaly defined in op instance
}



;// CONCATENATED MODULE: ./src/core/loadingstatus.js




/**
 * LoadingStatus class, manages asynchronous loading jobs
 *
 * @namespace external:CABLES#LoadingStatus
 * @hideconstructor
 * @class
 * @param patch
 */
const LoadingStatus = function (patch)
{
    EventTarget.apply(this);

    this._log = new Logger("LoadingStatus");
    this._loadingAssets = {};
    this._cbFinished = [];
    this._assetTasks = [];
    this._percent = 0;
    this._count = 0;
    this._countFinished = 0;
    this._order = 0;
    this._startTime = 0;
    this._patch = patch;
    this._wasFinishedPrinted = false;
    this._loadingAssetTaskCb = false;
};

LoadingStatus.prototype.setOnFinishedLoading = function (cb)
{
    this._cbFinished.push(cb);
};

LoadingStatus.prototype.getNumAssets = function ()
{
    return this._countFinished;
};

LoadingStatus.prototype.getProgress = function ()
{
    return this._percent;
};

LoadingStatus.prototype.checkStatus = function ()
{
    this._countFinished = 0;
    this._count = 0;

    for (const i in this._loadingAssets)
    {
        this._count++;
        if (!this._loadingAssets[i].finished)
        {
            this._countFinished++;
        }
    }

    this._percent = (this._count - this._countFinished) / this._count;

    if (this._countFinished === 0)
    {
        for (let j = 0; j < this._cbFinished.length; j++)
        {
            if (this._cbFinished[j])
            {
                const cb = this._cbFinished[j];
                setTimeout(() => { cb(this._patch); this.emitEvent("finishedAll"); }, 100);
            }
        }

        if (!this._wasFinishedPrinted)
        {
            this._wasFinishedPrinted = true;
            this.print();
        }
        this.emitEvent("finishedAll");
    }
};

LoadingStatus.prototype.getList = function ()
{
    let arr = [];
    for (const i in this._loadingAssets)
    {
        arr.push(this._loadingAssets[i]);
    }

    return arr;
};


LoadingStatus.prototype.getListJobs = function ()
{
    let arr = [];
    for (const i in this._loadingAssets)
    {
        if (!this._loadingAssets[i].finished)arr.push(this._loadingAssets[i].name);
    }

    return arr;
};

LoadingStatus.prototype.print = function ()
{
    if (this._patch.config.silent) return;

    const rows = [];

    for (const i in this._loadingAssets)
    {
        rows.push([
            this._loadingAssets[i].order,
            this._loadingAssets[i].type,
            this._loadingAssets[i].name,
            (this._loadingAssets[i].timeEnd - this._loadingAssets[i].timeStart) / 1000 + "s",
        ]);
    }

    this._log.groupCollapsed("finished loading " + this._order + " assets in " + (Date.now() - this._startTime) / 1000 + "s");
    this._log.table(rows);
    this._log.groupEnd();
};

LoadingStatus.prototype.finished = function (id)
{
    const l = this._loadingAssets[id];
    if (l)
    {
        if (l.finished) this._log.warn("loading job was already finished", l);

        if (l.op) l.op.setUiAttribs({ "loading": false });
        l.finished = true;
        l.timeEnd = Date.now();
    }

    this.checkStatus();
    this.emitEvent("finishedTask");
    return null;
};

LoadingStatus.prototype._startAssetTasks = function ()
{
    for (let i = 0; i < this._assetTasks.length; i++) this._assetTasks[i]();
    this._assetTasks.length = 0;
};

/**
 * delay an asset loading task, mainly to wait for ui to be finished loading and showing, and only then start loading assets
 * @function addAssetLoadingTask
 * @instance
 * @memberof LoadingStatus
 * @param {function} cb callback
 */
LoadingStatus.prototype.addAssetLoadingTask = function (cb)
{
    if (this._patch.isEditorMode() && !CABLES.UI.loaded)
    {
        this._assetTasks.push(cb);

        if (!this._loadingAssetTaskCb)window.gui.addEventListener("uiloaded", this._startAssetTasks.bind(this));
        this._loadingAssetTaskCb = true;
    }
    else
    {
        cb();
    }
    this.emitEvent("addAssetTask");
};

LoadingStatus.prototype.existByName = function (name)
{
    for (let i in this._loadingAssets)
    {
        if (this._loadingAssets[i].name == name && !this._loadingAssets[i].finished)
            return true;
    }
};

LoadingStatus.prototype.start = function (type, name, op)
{
    if (this._startTime == 0) this._startTime = Date.now();
    const id = generateUUID();

    name = name || "unknown";
    if (name.length > 100)name = name.substring(0, 100);


    if (op)op.setUiAttribs({ "loading": true });

    this._loadingAssets[id] = {
        "id": id,
        "op": op,
        "type": type,
        "name": name,
        "finished": false,
        "timeStart": Date.now(),
        "order": this._order,
    };
    this._order++;

    this.emitEvent("startTask");

    return id;
};



;// CONCATENATED MODULE: ./src/core/timer.js


/** @namespace CABLES */

const internalNow = function ()
{
    return window.performance.now();
};



/**
 * current time in milliseconds
 * @memberof CABLES
 * @function now
 * @static
 */
const now = function ()
{
    return internalNow();
};

// ----------------------------

/**
 * Measuring time
 * @namespace external:CABLES#Timer
 * @hideconstructor
 * @class
 */
const Timer = function ()
{
    EventTarget.apply(this);

    this._timeStart = internalNow();
    this._timeOffset = 0;

    this._currentTime = 0;
    this._lastTime = 0;
    this._paused = true;
    this._delay = 0;
    this.overwriteTime = -1;
};


Timer.prototype._internalNow = function ()
{
    if (this._ts) return this._ts;
    return internalNow();
};

Timer.prototype._getTime = function ()
{
    this._lastTime = (this._internalNow() - this._timeStart) / 1000;
    return this._lastTime + this._timeOffset;
};

Timer.prototype.setDelay = function (d)
{
    this._delay = d;
    this.emitEvent("timeChange");
};

/**
 * @function
 * @memberof Timer
 * @instance
 * @description returns true if timer is playing
 * @return {Boolean} value
 */
Timer.prototype.isPlaying = function ()
{
    return !this._paused;
};

/**
 * @function
 * @memberof Timer
 * @instance
 * @param ts
 * @description update timer
 * @return {Number} time
 */
Timer.prototype.update = function (ts)
{
    if (ts) this._ts = ts;
    if (this._paused) return;
    this._currentTime = this._getTime();

    return this._currentTime;
};

/**
 * @function
 * @memberof Timer
 * @instance
 * @return {Number} time in milliseconds
 */
Timer.prototype.getMillis = function ()
{
    return this.get() * 1000;
};

/**
 * @function
 * @memberof Timer
 * @instance
 * @return {Number} value time in seconds
 */
Timer.prototype.get = Timer.prototype.getTime = function ()
{
    if (this.overwriteTime >= 0) return this.overwriteTime - this._delay;
    return this._currentTime - this._delay;
};

/**
 * toggle between play/pause state
 * @function
 * @memberof Timer
 * @instance
 */
Timer.prototype.togglePlay = function ()
{
    if (this._paused) this.play();
    else this.pause();
};

/**
 * set current time
 * @function
 * @memberof Timer
 * @instance
 * @param {Number} t
 */
Timer.prototype.setTime = function (t)
{
    if (isNaN(t) || t < 0) t = 0;
    this._timeStart = this._internalNow();
    this._timeOffset = t;
    this._currentTime = t;
    this.emitEvent("timeChange");
};

Timer.prototype.setOffset = function (val)
{
    if (this._currentTime + val < 0)
    {
        this._timeStart = this._internalNow();
        this._timeOffset = 0;
        this._currentTime = 0;
    }
    else
    {
        this._timeOffset += val;
        this._currentTime = this._lastTime + this._timeOffset;
    }
    this.emitEvent("timeChange");
};

/**
 * (re)starts the timer
 * @function
 * @memberof Timer
 * @instance
 */
Timer.prototype.play = function ()
{
    this._timeStart = this._internalNow();
    this._paused = false;
    this.emitEvent("playPause");
};

/**
 * pauses the timer
 * @function
 * @memberof Timer
 * @instance
 */
Timer.prototype.pause = function ()
{
    this._timeOffset = this._currentTime;
    this._paused = true;
    this.emitEvent("playPause");
};



;// CONCATENATED MODULE: ./src/core/core_profiler.js


class Profiler
{
    constructor(patch)
    {
        this.startFrame = patch.getFrameNum();
        this.items = {};
        this.currentId = null;
        this.currentStart = 0;
        this._patch = patch;
    }

    getItems()
    {
        return this.items;
    }

    clear()
    {
        if (this.paused) return;
        this.items = {};
    }

    togglePause()
    {
        this.paused = !this.paused;
        if (!this.paused)
        {
            this.items = {};
            this.currentStart = performance.now();
        }
    }

    add(type, object)
    {
        if (this.paused) return;

        if (this.currentId !== null)
        {
            if (!object || object.id != this.currentId)
            {
                if (this.items[this.currentId])
                {
                    this.items[this.currentId].timeUsed += performance.now() - this.currentStart;

                    if (!this.items[this.currentId].peakTime || now() - this.items[this.currentId].peakTime > 5000)
                    {
                        this.items[this.currentId].peak = 0;
                        this.items[this.currentId].peakTime = now();
                    }
                    this.items[this.currentId].peak = Math.max(this.items[this.currentId].peak, performance.now() - this.currentStart);
                }
            }
        }

        if (object !== null)
        {
            if (!this.items[object.id])
            {
                this.items[object.id] = {
                    "numTriggers": 0,
                    "timeUsed": 0,
                };
            }

            if (this.items[object.id].lastFrame != this._patch.getFrameNum()) this.items[object.id].numTriggers = 0;

            this.items[object.id].lastFrame = this._patch.getFrameNum();
            this.items[object.id].numTriggers++;
            this.items[object.id].opid = object.op.id;
            this.items[object.id].title = object.op.name + "." + object.name;
            this.items[object.id].subPatch = object.op.uiAttribs.subPatch;

            this.currentId = object.id;
            this.currentStart = performance.now();
        }
        else
        {
            this.currentId = null;
        }
    }

    print()
    {
        console.log("--------");
        for (const i in this.items)
        {
            console.log(this.items[i].title + ": " + this.items[i].numTriggers + " / " + this.items[i].timeUsed);
        }
    }
}



;// CONCATENATED MODULE: ./src/core/cgl/constants.js
const SHADER = {
    // default attributes
    "SHADERVAR_VERTEX_POSITION": "vPosition",
    "SHADERVAR_VERTEX_NUMBER": "attrVertIndex",
    "SHADERVAR_VERTEX_NORMAL": "attrVertNormal",
    "SHADERVAR_VERTEX_TEXCOORD": "attrTexCoord",
    "SHADERVAR_INSTANCE_MMATRIX": "instMat",
    "SHADERVAR_VERTEX_COLOR": "attrVertColor",

    "SHADERVAR_INSTANCE_INDEX": "instanceIndex",

    // default uniforms
    "SHADERVAR_UNI_PROJMAT": "projMatrix",
    "SHADERVAR_UNI_VIEWMAT": "viewMatrix",
    "SHADERVAR_UNI_MODELMAT": "modelMatrix",
    "SHADERVAR_UNI_NORMALMAT": "normalMatrix",
    "SHADERVAR_UNI_INVVIEWMAT": "inverseViewMatrix",
    "SHADERVAR_UNI_INVPROJMAT": "invProjMatrix",
    "SHADERVAR_UNI_MATERIALID": "materialId",
    "SHADERVAR_UNI_OBJECTID": "objectId",

    "SHADERVAR_UNI_VIEWPOS": "camPos",
};


const BLEND_MODES = {
    "BLEND_NONE": 0,
    "BLEND_NORMAL": 1,
    "BLEND_ADD": 2,
    "BLEND_SUB": 3,
    "BLEND_MUL": 4,
};





const RAD2DEG = 180.0 / Math.PI;
const DEG2RAD = Math.PI / 180.0;

const constants_CONSTANTS = {
    "MATH": {
        "DEG2RAD": DEG2RAD,
        "RAD2DEG": RAD2DEG,
    },
    "SHADER": SHADER,
    "BLEND_MODES": BLEND_MODES,
};




;// CONCATENATED MODULE: ./src/core/cg/cg_uniform.js



class CgUniform
{
    constructor(__shader, __type, __name, _value, _port2, _port3, _port4, _structUniformName, _structName, _propertyName)
    {
        this._log = new Logger("cg_uniform");
        this._type = __type;
        this._name = __name;
        this._shader = __shader;
        this._value = 0.00001;
        this._oldValue = null;
        this._port = null;
        this._structName = _structName;
        this._structUniformName = _structUniformName;
        this._propertyName = _propertyName;

        this._shader._addUniform(this);
        this.needsUpdate = true;
        this.shaderType = null;
        this.comment = null;

        if (__type == "f")
        {
            this.set = this.setValue = this.setValueF.bind(this);
            this.updateValue = this.updateValueF.bind(this);
        }
        else if (__type == "f[]")
        {
            this.set = this.setValue = this.setValueArrayF.bind(this);
            this.updateValue = this.updateValueArrayF.bind(this);
        }
        else if (__type == "2f[]")
        {
            this.set = this.setValue = this.setValueArray2F.bind(this);
            this.updateValue = this.updateValueArray2F.bind(this);
        }
        else if (__type == "3f[]")
        {
            this.set = this.setValue = this.setValueArray3F.bind(this);
            this.updateValue = this.updateValueArray3F.bind(this);
        }
        else if (__type == "4f[]")
        {
            this.set = this.setValue = this.setValueArray4F.bind(this);
            this.updateValue = this.updateValueArray4F.bind(this);
        }
        else if (__type == "i")
        {
            this.set = this.setValue = this.setValueI.bind(this);
            this.updateValue = this.updateValueI.bind(this);
        }
        else if (__type == "2i")
        {
            this.set = this.setValue = this.setValue2I.bind(this);
            this.updateValue = this.updateValue2I.bind(this);
        }
        else if (__type == "3i")
        {
            this.set = this.setValue = this.setValue3I.bind(this);
            this.updateValue = this.updateValue3I.bind(this);
        }
        else if (__type == "4i")
        {
            this.set = this.setValue = this.setValue4I.bind(this);
            this.updateValue = this.updateValue4I.bind(this);
        }
        else if (__type == "b")
        {
            this.set = this.setValue = this.setValueBool.bind(this);
            this.updateValue = this.updateValueBool.bind(this);
        }
        else if (__type == "4f")
        {
            this.set = this.setValue = this.setValue4F.bind(this);
            this.updateValue = this.updateValue4F.bind(this);
        }
        else if (__type == "3f")
        {
            this.set = this.setValue = this.setValue3F.bind(this);
            this.updateValue = this.updateValue3F.bind(this);
        }
        else if (__type == "2f")
        {
            this.set = this.setValue = this.setValue2F.bind(this);
            this.updateValue = this.updateValue2F.bind(this);
        }
        else if (__type == "t")
        {
            this.set = this.setValue = this.setValueT.bind(this);
            this.updateValue = this.updateValueT.bind(this);
        }
        else if (__type == "sampler")
        {
            if (this.setValueAny)
            {
                this.set = this.setValue = this.setValueAny.bind(this);
                this.updateValue = this.updateValueAny.bind(this);
            }
        }
        else if (__type == "tc")
        {
            this.set = this.setValue = this.setValueT.bind(this);
            this.updateValue = this.updateValueT.bind(this);
        }
        else if (__type == "t[]")
        {
            this.set = this.setValue = this.setValueArrayT.bind(this);
            this.updateValue = this.updateValueArrayT.bind(this);
        }
        else if (__type == "m4" || __type == "m4[]")
        {
            this.set = this.setValue = this.setValueM4.bind(this);
            this.updateValue = this.updateValueM4.bind(this);
        }
        else
        {
            // console.error("unknown");
            this._log.error("Unknown uniform type " + __type);
        }

        if (typeof _value == "object" && _value instanceof Port)
        {
            this._port = _value;
            this._value = this._port.get();


            if (_port2 && _port3 && _port4)
            {
                if (!(_port2 instanceof Port) || !(_port3 instanceof Port) || !(_port4 instanceof Port))
                {
                    this._log.error("[cgl_uniform] mixed port/value parameter for vec4 ", this._name);
                }

                this._value = [0, 0, 0, 0];
                this._port2 = _port2;
                this._port3 = _port3;
                this._port4 = _port4;

                this._port.on("change", this.updateFromPort4f.bind(this));
                this._port2.on("change", this.updateFromPort4f.bind(this));
                this._port3.on("change", this.updateFromPort4f.bind(this));
                this._port4.on("change", this.updateFromPort4f.bind(this));

                // this._port.onChange = this._port2.onChange = this._port3.onChange = this._port4.onChange = this.updateFromPort4f.bind(this);
                this.updateFromPort4f();
            }
            else if (_port2 && _port3)
            {
                if (!(_port2 instanceof Port) || !(_port3 instanceof Port))
                {
                    this._log.error("[cgl_uniform] mixed port/value parameter for vec4 ", this._name);
                }

                this._value = [0, 0, 0];
                this._port2 = _port2;
                this._port3 = _port3;
                // this._port.onChange = this._port2.onChange = this._port3.onChange = this.updateFromPort3f.bind(this);
                this._port.on("change", this.updateFromPort3f.bind(this));
                this._port2.on("change", this.updateFromPort3f.bind(this));
                this._port3.on("change", this.updateFromPort3f.bind(this));

                this.updateFromPort3f();
            }
            else if (_port2)
            {
                if (!(_port2 instanceof Port))
                {
                    this._log.error("[cgl_uniform] mixed port/value parameter for vec4 ", this._name);
                }

                this._value = [0, 0];
                this._port2 = _port2;
                // this._port.onChange = this._port2.onChange = this.updateFromPort2f.bind(this);
                this._port.on("change", this.updateFromPort2f.bind(this));
                this._port2.on("change", this.updateFromPort2f.bind(this));

                this.updateFromPort2f();
            }
            else
            {
                // this._port.on = this.updateFromPort.bind(this);
                this._port.on("change", this.updateFromPort.bind(this));
            }
        }
        else this._value = _value;


        if (this._value == undefined)
        {
            console.log("value undefined", this);
            this._value = 0;
        }

        this.setValue(this._value);

        this.needsUpdate = true;
    }

    getType()
    {
        return this._type;
    }

    get type()
    {
        return this._type;
    }

    get name()
    {
        return this._name;
    }

    getName()
    {
        return this._name;
    }

    getValue()
    {
        return this._value;
    }

    getShaderType()
    {
        return this.shaderType;
    }

    isStructMember()
    {
        return !!this._structName;
    }


    updateFromPort4f()
    {
        this._value[0] = this._port.get();
        this._value[1] = this._port2.get();
        this._value[2] = this._port3.get();
        this._value[3] = this._port4.get();
        this.setValue(this._value);
    }

    updateFromPort3f()
    {
        this._value[0] = this._port.get();
        this._value[1] = this._port2.get();
        this._value[2] = this._port3.get();
        this.setValue(this._value);
    }

    updateFromPort2f()
    {
        this._value[0] = this._port.get();
        this._value[1] = this._port2.get();
        this.setValue(this._value);
    }

    updateFromPort()
    {
        this.setValue(this._port.get());
    }
}

/* harmony default export */ const cg_uniform = (CgUniform);

;// CONCATENATED MODULE: ./src/core/cgl/cgl_shader_uniform.js




/**
 * Shader uniforms
 *
 * types:
 * <pre>
 * f    - float
 * 2f   - vec2
 * 3f   - vec3
 * 4f   - vec4
 * i    - integer
 * t    - texture
 * m4   - mat4, 4x4 float matrix
 * f[]  - array of floats
 * 2f[] - array of float vec2
 * 3f[] - array of float vec3
 * 4f[] - array of float vec4
 * </pre>
 *
 * @namespace external:CGL
 * @class
 * @param {Shader} shader
 * @param {String} [type=f]
 * @param {String} name
 * @param {Number|Port} value  can be a Number,Matrix or Port
 * @example
 * // bind float uniform called myfloat and initialize with value 1.0
 * const unir=new CGL.Uniform(shader,'f','myfloat',1.0);
 * unir.setValue(1.0);
 *
 * // bind float uniform called myfloat and automatically set it to input port value
 * const myPort=op.inFloat("input");
 * const pv=new CGL.Uniform(shader,'f','myfloat',myPort);
 *
 */


// export const Uniform(__shader, __type, __name, _value, _port2, _port3, _port4, _structUniformName, _structName, _propertyName)

class Uniform extends cg_uniform
{
    constructor(__shader, __type, __name, _value, _port2, _port3, _port4, _structUniformName, _structName, _propertyName)
    {
        super(__shader, __type, __name, _value, _port2, _port3, _port4, _structUniformName, _structName, _propertyName);
        this._loc = -1;
        this._cgl = __shader._cgl;
    }

    get name()
    {
        return this._name;
    }

    copy(newShader)
    {
        const uni = new Uniform(newShader, this._type, this._name, this._value, this._port2, this._port3, this._port4, this._structUniformName, this._structName, this._propertyName);
        uni.shaderType = this.shaderType;
        return uni;
    }

    /**
     * returns type as glsl type string. e.g. 'f' returns 'float'
     * @function getGlslTypeString
     * @memberof Uniform
     * @instance
     * @return {string} type as string
     */
    getGlslTypeString()
    {
        return Uniform.glslTypeString(this._type);
    }

    _isValidLoc()
    {
        return this._loc != -1;// && this._loc != null;
    }

    resetLoc()
    {
        this._loc = -1;
        this.needsUpdate = true;
    }

    bindTextures() {}

    getLoc()
    {
        return this._loc;
    }

    updateFromPort4f()
    {
        this._value[0] = this._port.get();
        this._value[1] = this._port2.get();
        this._value[2] = this._port3.get();
        this._value[3] = this._port4.get();
        this.setValue(this._value);
    }

    updateFromPort3f()
    {
        this._value[0] = this._port.get();
        this._value[1] = this._port2.get();
        this._value[2] = this._port3.get();
        this.setValue(this._value);
    }

    updateFromPort2f()
    {
        this._value[0] = this._port.get();
        this._value[1] = this._port2.get();
        this.setValue(this._value);
    }

    updateFromPort()
    {
        this.setValue(this._port.get());
    }

    updateValueF()
    {
        if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
        else this.needsUpdate = false;

        this._shader.getCgl().gl.uniform1f(this._loc, this._value);
        this._cgl.profileData.profileUniformCount++;
    }

    setValueF(v)
    {
        if (v != this._value)
        {
            this.needsUpdate = true;
            this._value = v;
        }
    }

    updateValueI()
    {
        if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
        else this.needsUpdate = false;

        this._shader.getCgl().gl.uniform1i(this._loc, this._value);
        this._cgl.profileData.profileUniformCount++;
    }

    updateValue2I()
    {
        if (!this._value) return;

        if (!this._isValidLoc())
        {
            this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
            this._cgl.profileData.profileShaderGetUniform++;
            this._cgl.profileData.profileShaderGetUniformName = this._name;
        }

        this._shader.getCgl().gl.uniform2i(this._loc, this._value[0], this._value[1]);

        this.needsUpdate = false;
        this._cgl.profileData.profileUniformCount++;
    }

    updateValue3I()
    {
        if (!this._value) return;
        if (!this._isValidLoc())
        {
            this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
            this._cgl.profileData.profileShaderGetUniform++;
            this._cgl.profileData.profileShaderGetUniformName = this._name;
        }

        this._shader.getCgl().gl.uniform3i(this._loc, this._value[0], this._value[1], this._value[2]);
        this.needsUpdate = false;
        this._cgl.profileData.profileUniformCount++;
    }

    updateValue4I()
    {
        if (!this._isValidLoc())
        {
            this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
            this._cgl.profileData.profileShaderGetUniform++;
            this._cgl.profileData.profileShaderGetUniformName = this._name;
        }
        this._shader.getCgl().gl.uniform4i(this._loc, this._value[0], this._value[1], this._value[2], this._value[3]);
        this._cgl.profileData.profileUniformCount++;
    }

    setValueI(v)
    {
        if (v != this._value)
        {
            this.needsUpdate = true;
            this._value = v;
        }
    }

    setValue2I(v)
    {
        if (!v) return;
        if (!this._oldValue)
        {
            this._oldValue = [v[0] - 1, 1];
            this.needsUpdate = true;
        }
        else if (v[0] != this._oldValue[0] || v[1] != this._oldValue[1])
        {
            this._oldValue[0] = v[0];
            this._oldValue[1] = v[1];
            this.needsUpdate = true;
        }

        this._value = v;
    }

    setValue3I(v)
    {
        if (!v) return;
        if (!this._oldValue)
        {
            this._oldValue = [v[0] - 1, 1, 2];
            this.needsUpdate = true;
        }
        else if (v[0] != this._oldValue[0] || v[1] != this._oldValue[1] || v[2] != this._oldValue[2])
        {
            this._oldValue[0] = v[0];
            this._oldValue[1] = v[1];
            this._oldValue[2] = v[2];
            this.needsUpdate = true;
        }

        this._value = v;
    }

    setValue4I(v)
    {
        this.needsUpdate = true;
        this._value = v || vec4.create();
    }

    updateValueBool()
    {
        if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
        else this.needsUpdate = false;
        this._shader.getCgl().gl.uniform1i(this._loc, this._value ? 1 : 0);

        this._cgl.profileData.profileUniformCount++;
    }

    setValueBool(v)
    {
        if (v != this._value)
        {
            this.needsUpdate = true;
            this._value = v;
        }
    }

    setValueArray4F(v)
    {
        this.needsUpdate = true;
        this._value = v;
    }

    updateValueArray4F()
    {
        if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
        else this.needsUpdate = false;

        if (!this._value) return;
        this._shader.getCgl().gl.uniform4fv(this._loc, this._value);
        this._cgl.profileData.profileUniformCount++;
    }

    setValueArray3F(v)
    {
        this.needsUpdate = true;
        this._value = v;
    }

    updateValueArray3F()
    {
        if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
        else this.needsUpdate = false;

        if (!this._value) return;
        this._shader.getCgl().gl.uniform3fv(this._loc, this._value);
        this._cgl.profileData.profileUniformCount++;
    }

    setValueArray2F(v)
    {
        this.needsUpdate = true;
        this._value = v;
    }

    updateValueArray2F()
    {
        if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
        else this.needsUpdate = false;

        if (!this._value) return;
        this._shader.getCgl().gl.uniform2fv(this._loc, this._value);
        this._cgl.profileData.profileUniformCount++;
    }

    setValueArrayF(v)
    {
        this.needsUpdate = true;
        this._value = v;
    }

    updateValueArrayF()
    {
        if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
        else this.needsUpdate = false;

        if (!this._value) return;
        this._shader.getCgl().gl.uniform1fv(this._loc, this._value);
        this._cgl.profileData.profileUniformCount++;
    }

    setValueArrayT(v)
    {
        this.needsUpdate = true;
        this._value = v;
    }


    updateValue3F()
    {
        if (!this._value) return;
        if (!this._isValidLoc())
        {
            this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
            this._cgl.profileData.profileShaderGetUniform++;
            this._cgl.profileData.profileShaderGetUniformName = this._name;
        }

        this._shader.getCgl().gl.uniform3f(this._loc, this._value[0], this._value[1], this._value[2]);
        this.needsUpdate = false;
        this._cgl.profileData.profileUniformCount++;
    }

    setValue3F(v)
    {
        if (!v) return;
        if (!this._oldValue)
        {
            this._oldValue = [v[0] - 1, 1, 2];
            this.needsUpdate = true;
        }
        else if (v[0] != this._oldValue[0] || v[1] != this._oldValue[1] || v[2] != this._oldValue[2])
        {
            this._oldValue[0] = v[0];
            this._oldValue[1] = v[1];
            this._oldValue[2] = v[2];
            this.needsUpdate = true;
        }

        this._value = v;
    }

    updateValue2F()
    {
        if (!this._value) return;

        if (!this._isValidLoc())
        {
            this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
            this._cgl.profileData.profileShaderGetUniform++;
            this._cgl.profileData.profileShaderGetUniformName = this._name;
        }

        this._shader.getCgl().gl.uniform2f(this._loc, this._value[0], this._value[1]);
        this.needsUpdate = false;
        this._cgl.profileData.profileUniformCount++;
    }

    setValue2F(v)
    {
        if (!v) return;
        if (!this._oldValue)
        {
            this._oldValue = [v[0] - 1, 1];
            this.needsUpdate = true;
        }
        else if (v[0] != this._oldValue[0] || v[1] != this._oldValue[1])
        {
            this._oldValue[0] = v[0];
            this._oldValue[1] = v[1];
            this.needsUpdate = true;
        }
        this._value = v;
    }

    updateValue4F()
    {
        if (!this._isValidLoc())
        {
            this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
            this._cgl.profileData.profileShaderGetUniform++;
            this._cgl.profileData.profileShaderGetUniformName = this._name;
        }

        if (!this._value)
        {
            this._log.warn("no value for uniform", this._name, this);
            this._value = [0, 0, 0, 0];
        }

        this.needsUpdate = false;
        this._shader.getCgl().gl.uniform4f(this._loc, this._value[0], this._value[1], this._value[2], this._value[3]);
        this._cgl.profileData.profileUniformCount++;
    }

    setValue4F(v)
    {
        if (typeof this.value == "number") this.value = vec4.create(); // this should not be needed, but somehow it crashes with some shadermods

        if (!v) return;
        if (!this._oldValue)
        {
            this._oldValue = [v[0] - 1, 1, 2, 3];
            this.needsUpdate = true;
        }
        else if (v[0] != this._oldValue[0] || v[1] != this._oldValue[1] || v[2] != this._oldValue[2] || v[3] != this._oldValue[3])
        {
            this._oldValue[0] = v[0];
            this._oldValue[1] = v[1];
            this._oldValue[2] = v[2];
            this.needsUpdate = true;
        }

        this._value = v;
    }

    updateValueM4()
    {
        if (!this._isValidLoc())
        {
            this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
            this._cgl.profileData.profileShaderGetUniform++;
            this._cgl.profileData.profileShaderGetUniformName = this._name;
        }
        if (!this._value || this._value.length % 16 != 0) return console.log("this.name", this._name, this._value);

        this._shader.getCgl().gl.uniformMatrix4fv(this._loc, false, this._value);
        this._cgl.profileData.profileUniformCount++;
    }

    setValueM4(v)
    {
        this.needsUpdate = true;
        this._value = v || mat4.create();
    }

    updateValueArrayT()
    {
        if (!this._isValidLoc()) this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
        else this.needsUpdate = false;

        if (!this._value) return;
        this._shader.getCgl().gl.uniform1iv(this._loc, this._value);
        this._cgl.profileData.profileUniformCount++;
    }

    updateValueT()
    {
        if (!this._isValidLoc())
        {
            this._loc = this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(), this._name);
            this._cgl.profileData.profileShaderGetUniform++;
            this._cgl.profileData.profileShaderGetUniformName = this._name;
        }

        this._cgl.profileData.profileUniformCount++;
        this._shader.getCgl().gl.uniform1i(this._loc, this._value);
        this.needsUpdate = false;
    }

    setValueT(v)
    {
        this.needsUpdate = true;
        this._value = v;
    }
}


Uniform.glslTypeString = (t) =>
{
    if (t == "f") return "float";
    if (t == "b") return "bool";
    if (t == "i") return "int";
    if (t == "2i") return "ivec2";
    if (t == "2f") return "vec2";
    if (t == "3f") return "vec3";
    if (t == "4f") return "vec4";
    if (t == "m4") return "mat4";

    if (t == "t") return "sampler2D";
    if (t == "tc") return "samplerCube";

    if (t == "3f[]") return null; // ignore this for now...
    if (t == "m4[]") return null; // ignore this for now...
    if (t == "f[]") return null; // ignore this for now...

    console.warn("[CGL UNIFORM] unknown glsl type string ", t);
};


/**
 * @function setValue
 * @memberof Uniform
 * @instance
 * @param {Number|Array|Matrix|Texture} value
 */



;// CONCATENATED MODULE: ./src/core/cg/cg_texture.js
const DEFAULT_TEXTURE_SIZE = 8;

class CgTexture
{
    constructor(options = {})
    {
        this.id = CABLES.uuid();
        this.width = 0;
        this.height = 0;
        this.name = "unknown";

        options = options || {};
        this.pixelFormat = options.pixelFormat || CgTexture.PFORMATSTR_RGBA8UB;

        this.name = options.name || "unknown";

        if (!options.width) options.width = DEFAULT_TEXTURE_SIZE;
        if (!options.height) options.height = DEFAULT_TEXTURE_SIZE;
    }
}


CgTexture.getDefaultTextureData = (name, size, options = {}) =>
{
    if (name == "empty")
    {
        return new Uint8Array(size * size * 4).fill(0);
    }
    else
    if (name == "color")
    {
        const data = new Uint8Array(size * size * 4);
        let r = options.r || 1;
        let g = options.g || 1;
        let b = options.b || 1;

        for (let x = 0; x < size * size; x++)
        {
            data[x * 4 + 0] = r;
            data[x * 4 + 1] = g;
            data[x * 4 + 2] = b;
            data[x * 4 + 3] = 255;
        }
        return data;
    }
    else
    if (name == "randomUInt")
    {
        const data = new Uint8Array(size * size * 4);

        for (let x = 0; x < size * size; x++)
        {
            data[x * 4 + 0] = Math.random() * 255;
            data[x * 4 + 1] = Math.random() * 255;
            data[x * 4 + 2] = Math.random() * 255;
            data[x * 4 + 3] = 255;
        }
        return data;
    }
    else
    if (name == "random" || name == "randomFloat")
    {
        const data = new Float32Array(size * size * 4);

        for (let x = 0; x < size * size; x++)
        {
            data[x * 4 + 0] = (Math.random() - 0.5) * 2.0;
            data[x * 4 + 1] = (Math.random() - 0.5) * 2.0;
            data[x * 4 + 2] = (Math.random() - 0.5) * 2.0;
            data[x * 4 + 3] = 1;
        }
        return data;
    }
    else
    if (name == "stripes")
    {
        const arr = [];

        let r = options.r;
        let g = options.g;
        let b = options.b;

        if (r === undefined)r = 1;
        if (g === undefined)g = 1;
        if (b === undefined)b = 1;

        for (let y = 0; y < size; y++)
        {
            for (let x = 0; x < size; x++)
            {
                if ((x + y) % 64 < 32)
                {
                    arr.push((200 + (y / size) * 25 + (x / size) * 25) * r);
                    arr.push((200 + (y / size) * 25 + (x / size) * 25) * g);
                    arr.push((200 + (y / size) * 25 + (x / size) * 25) * b);
                }
                else
                {
                    arr.push((40 + (y / size) * 25 + (x / size) * 25) * r);
                    arr.push((40 + (y / size) * 25 + (x / size) * 25) * g);
                    arr.push((40 + (y / size) * 25 + (x / size) * 25) * b);
                }
                arr.push(255);
            }
        }

        return new Uint8Array(arr);
    }
    else
    {
        console.warn("unknown default texture", name);
        return CgTexture.getDefaultTextureData("stripes", size, { "r": 1, "g": 0, "b": 0 });
    }
};



CgTexture.FILTER_NEAREST = 0;
CgTexture.FILTER_LINEAR = 1;
CgTexture.FILTER_MIPMAP = 2;

CgTexture.WRAP_REPEAT = 0;
CgTexture.WRAP_MIRRORED_REPEAT = 1;
CgTexture.WRAP_CLAMP_TO_EDGE = 2;

CgTexture.TYPE_DEFAULT = 0;
CgTexture.TYPE_DEPTH = 1;
CgTexture.TYPE_FLOAT = 2;


CgTexture.PFORMATSTR_RGB565 = "RGB 5/6/5bit ubyte";

CgTexture.PFORMATSTR_R8UB = "R 8bit ubyte";
CgTexture.PFORMATSTR_RG8UB = "RG 8bit ubyte";
CgTexture.PFORMATSTR_RGB8UB = "RGB 8bit ubyte";
CgTexture.PFORMATSTR_RGBA8UB = "RGBA 8bit ubyte";

CgTexture.PFORMATSTR_SRGBA8 = "SRGBA 8bit ubyte";

CgTexture.PFORMATSTR_R11FG11FB10F = "RGB 11/11/10bit float";

CgTexture.PFORMATSTR_R16F = "R 16bit float";
CgTexture.PFORMATSTR_RG16F = "RG 16bit float";
CgTexture.PFORMATSTR_RGB16F = "RGB 16bit float";
CgTexture.PFORMATSTR_RGBA16F = "RGBA 16bit float";


CgTexture.PFORMATSTR_R32F = "R 32bit float";
CgTexture.PFORMATSTR_RG32F = "RG 32bit float";
CgTexture.PFORMATSTR_RGB32F = "RGB 32bit float";
CgTexture.PFORMATSTR_RGBA32F = "RGBA 32bit float";

CgTexture.PFORMATSTR_DEPTH = "DEPTH";


CgTexture.PIXELFORMATS = [

    CgTexture.PFORMATSTR_RGB565,

    CgTexture.PFORMATSTR_R8UB,
    CgTexture.PFORMATSTR_RG8UB,
    CgTexture.PFORMATSTR_RGB8UB,
    CgTexture.PFORMATSTR_RGBA8UB,

    CgTexture.PFORMATSTR_SRGBA8,

    CgTexture.PFORMATSTR_R11FG11FB10F,
    CgTexture.PFORMATSTR_R16F,
    CgTexture.PFORMATSTR_RG16F,
    CgTexture.PFORMATSTR_RGBA16F,

    CgTexture.PFORMATSTR_R32F,
    CgTexture.PFORMATSTR_RGBA32F

];

;// CONCATENATED MODULE: ./src/core/cgl/cgl_texture.js




const cgl_texture_DEFAULT_TEXTURE_SIZE = 8;

/**
 * A Texture
 * @namespace external:CGL
 * @class
 * @param {Context} __cgl cgl
 * @param {Object} options
 * @hideconstructor
 * @example
 * // generate a 256x256 pixel texture of random colors
 * const size=256;
 * const data = new Uint8Array(size*size*4);
 *
 * for(var x=0;x<size*size*4;x++) data[ x*4+3]=255;
 *
 * const tex=new CGL.Texture(cgl);
 * tex.initFromData(data,size,size,CGL.Texture.FILTER_NEAREST,CGL.Texture.WRAP_REPEAT);
 */
class Texture extends CgTexture
{
    constructor(__cgl, options = {})
    {
        super(options);
        if (!__cgl) throw new Error("no cgl");
        this._log = new Logger("cgl_texture");
        this._cgl = __cgl;
        this.tex = this._cgl.gl.createTexture();
        this.loading = false;
        this.flip = true;
        this.flipped = false;
        this.shadowMap = false;
        this.deleted = false;
        this.image = null;
        this.anisotropic = 0;
        this.filter = Texture.FILTER_NEAREST;
        this.wrap = Texture.WRAP_CLAMP_TO_EDGE;
        this.texTarget = this._cgl.gl.TEXTURE_2D;
        if (options && options.type) this.texTarget = options.type;
        this.textureType = Texture.TYPE_DEFAULT;
        this.unpackAlpha = true;
        this._fromData = true;

        this._glDataType = -1;
        this._glInternalFormat = -1;
        this._glDataFormat = -1;


        if (options)
        {
            if (options.isDepthTexture) this.textureType = Texture.TYPE_DEPTH;
            if (options.isFloatingPointTexture === true) this.textureType = Texture.TYPE_FLOAT;

            if ("textureType" in options) this.textureType = options.textureType;
            if ("filter" in options) this.filter = options.filter;
            if ("wrap" in options) this.wrap = options.wrap;
            if ("unpackAlpha" in options) this.unpackAlpha = options.unpackAlpha;
            if ("flip" in options) this.flip = options.flip;
            if ("shadowMap" in options) this.shadowMap = options.shadowMap;
            if ("anisotropic" in options) this.anisotropic = options.anisotropic;
        }
        else
        {
            options = {};
        }

        if (!options.pixelFormat && options.isFloatingPointTexture) this.pixelFormat = Texture.PFORMATSTR_RGBA32F;

        if (this.textureType == Texture.TYPE_DEPTH) this.pixelFormat = Texture.PFORMATSTR_DEPTH;

        this._cgl.profileData.profileTextureNew++;


        this.setFormat(Texture.setUpGlPixelFormat(this._cgl, this.pixelFormat));
        this._cgl.profileData.addHeavyEvent("texture created", this.name, options.width + "x" + options.height);

        this.setSize(options.width, options.height);
        this.getInfoOneLine();
    }



    isFloatingPoint()
    {
        return Texture.isPixelFormatFloat(this.pixelFormat);
    }

    /**
     * returns true if otherTexture has same options (width/height/filter/wrap etc)
     * @function compareSettings
     * @memberof Texture
     * @instance
     * @param {Texture} tex otherTexture
     * @returns {Boolean}
     */
    compareSettings(tex)
    {
    // if (!tex) { this._log.warn("compare: no tex"); return false; }
    // if (tex.width != this.width) this._log.warn("tex.width not equal", tex.width, this.width);
    // if (tex.height != this.height) this._log.warn("tex.height not equal", tex.height, this.height);
    // if (tex.filter != this.filter) this._log.warn("tex.filter not equal");
    // if (tex.wrap != this.wrap) this._log.warn("tex.wrap not equal");
    // if (tex.textureType != this.textureType) this._log.warn("tex.textureType not equal");
    // if (tex.unpackAlpha != this.unpackAlpha) this._log.warn("tex.unpackAlpha not equal");
    // if (tex.anisotropic != this.anisotropic) this._log.warn("tex.anisotropic not equal");
    // if (tex.shadowMap != this.shadowMap) this._log.warn("tex.shadowMap not equal");
    // if (tex.texTarget != this.texTarget) this._log.warn("tex.texTarget not equal");
    // if (tex.flip != this.flip) this._log.warn("tex.flip not equal");

        if (!tex) return false;
        return (
            tex.width == this.width &&
            tex.height == this.height &&
            tex.filter == this.filter &&
            tex.wrap == this.wrap &&
            tex.textureType == this.textureType &&
            tex.unpackAlpha == this.unpackAlpha &&
            tex.anisotropic == this.anisotropic &&
            tex.shadowMap == this.shadowMap &&
            tex.texTarget == this.texTarget &&
            tex.flip == this.flip
        );
    }

    /**
     * returns a new texture with the same settings (does not copy texture itself)
     * @function clone
     * @memberof Texture
     * @instance
     * @returns {Texture}
     */
    clone()
    {
        const newTex = new Texture(this._cgl, {
            "name": this.name,
            "filter": this.filter,
            "anisotropic": this.anisotropic,
            "wrap": this.wrap,
            "textureType": this.textureType,
            "pixelFormat": this.pixelFormat,
            "unpackAlpha": this.unpackAlpha,
            "flip": this.flip,
            "width": this.width,
            "height": this.height,
        });

        this._cgl.profileData.addHeavyEvent("texture created", this.name, this.width + "x" + this.height);

        if (!this.compareSettings(newTex))
        {
            this._log.error("Cloned texture settings do not compare!");
            this._log.error(this);
            this._log.error(newTex);
        }

        return newTex;
    }


    setFormat(o)
    {
        this.pixelFormat = o.pixelFormat;
        this._glDataFormat = o.glDataFormat;
        this._glInternalFormat = o.glInternalFormat;
        this._glDataType = o.glDataType;
    }



    /**
     * set pixel size of texture
     * @function setSize
     * @memberof Texture
     * @instance
     * @param {Number} w width
     * @param {Number} h height
     */
    setSize(w, h)
    {
        if (this._cgl.aborted) return;
        if (w != w || w <= 0 || !w) w = cgl_texture_DEFAULT_TEXTURE_SIZE;
        if (h != h || h <= 0 || !h) h = cgl_texture_DEFAULT_TEXTURE_SIZE;

        if (w > this._cgl.maxTexSize || h > this._cgl.maxTexSize) this._log.error("texture size too big! " + w + "x" + h + " / max: " + this._cgl.maxTexSize);

        w = Math.min(w, this._cgl.maxTexSize);
        h = Math.min(h, this._cgl.maxTexSize);

        w = Math.floor(w);
        h = Math.floor(h);
        if (this.width == w && this.height == h) return;

        w = this._cgl.checkTextureSize(w);
        h = this._cgl.checkTextureSize(h);

        this.width = w;
        this.height = h;
        this.deleted = false;

        this.setFormat(Texture.setUpGlPixelFormat(this._cgl, this.pixelFormat));

        this.shortInfoString = this.getInfoOneLine();// w + "x" + h + "";

        this._cgl.gl.bindTexture(this.texTarget, this.tex);
        this._cgl.profileData.profileTextureResize++;

        const uarr = null;

        this._cgl.gl.texImage2D(this.texTarget, 0, this._glInternalFormat, w, h, 0, this._glDataFormat, this._glDataType, uarr);

        this._setFilter();

        this.updateMipMap();

        this._cgl.gl.bindTexture(this.texTarget, null);
    }


    /**
     * @function initFromData
     * @memberof Texture
     * @instance
     * @description create texturem from rgb data
     * @param {Array<Number>} data rgb color array [r,g,b,a,r,g,b,a,...]
     * @param {Number} w width
     * @param {Number} h height
     * @param {Number} filter
     * @param {Number} wrap
     */
    initFromData(data, w, h, filter, wrap)
    {
        this.filter = filter;
        this.wrap = wrap;
        if (filter == undefined) this.filter = Texture.FILTER_LINEAR;
        if (wrap == undefined) this.wrap = Texture.WRAP_CLAMP_TO_EDGE;
        this.width = w;
        this.height = h;
        this._fromData = true;
        this.deleted = false;

        if (this.height > this._cgl.maxTexSize || this.width > this._cgl.maxTexSize)
        {
            const t = CGL.Texture.getTempTexture(this._cgl);
            this.width = t.width;
            this.height = t.height;
            this.tex = t.tex;
            this._log.warn("[cgl_texture] texture size too big!", this.width, this.height, this._cgl.maxTexSize);
            return;
        }

        if (this.flip) this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_FLIP_Y_WEBGL, this.flip);

        this._cgl.gl.bindTexture(this.texTarget, this.tex);

        this.setFormat(Texture.setUpGlPixelFormat(this._cgl, this.pixelFormat));

        this._cgl.gl.texImage2D(this.texTarget, 0, this._glInternalFormat, w, h, 0, this._glDataFormat, this._glDataType, data);

        this._setFilter();
        this.updateMipMap();

        if (this.flip) this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_FLIP_Y_WEBGL, false);
        this._cgl.gl.bindTexture(this.texTarget, null);
    }

    updateMipMap()
    {
        if ((this._cgl.glVersion == 2 || this.isPowerOfTwo()) && this.filter == Texture.FILTER_MIPMAP)
        {
            this._cgl.gl.generateMipmap(this.texTarget);
            this._cgl.profileData.profileGenMipMap++;
        }
    }

    /**
     * set texture data from an image/canvas object
     * @function initTexture
     * @memberof Texture
     * @instance
     * @param {Object} img image
     * @param {Number} filter
     */
    initTexture(img, filter)
    {
        this._cgl.printError("before initTexture");
        this._cgl.checkFrameStarted("texture inittexture");
        this._fromData = false;

        this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.unpackAlpha);
        if (img.width || img.videoWidth) this.width = img.videoWidth || img.width;
        if (img.height || img.videoHeight) this.height = img.videoHeight || img.height;

        if (filter !== undefined) this.filter = filter; // todo: can we remove this filter param?

        if (img.height > this._cgl.maxTexSize || img.width > this._cgl.maxTexSize)
        {
            const t = CGL.Texture.getTempTexture(this._cgl);
            this.width = t.width;
            this.height = t.height;
            this.tex = t.tex;
            this._log.warn("[cgl_texture] texture size too big!", img.width, img.height, this._cgl.maxTexSize);
            return;
        }

        this._cgl.gl.bindTexture(this.texTarget, this.tex);

        this.deleted = false;
        this.flipped = !this.flip;
        if (this.flipped) this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_FLIP_Y_WEBGL, this.flipped);


        this.setFormat(Texture.setUpGlPixelFormat(this._cgl, this.pixelFormat));

        this._cgl.gl.texImage2D(this.texTarget, 0, this._glInternalFormat, this._glDataFormat, this._glDataType, img);

        this._setFilter();
        this.updateMipMap();

        this._cgl.gl.bindTexture(this.texTarget, null);
        this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
        if (this.flipped) this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_FLIP_Y_WEBGL, false);

        this.getInfoOneLine();
        this._cgl.printError("initTexture");
    }

    /**
     * delete texture. use this when texture is no longer needed
     * @function delete
     * @memberof Texture
     * @instance
     */
    dispose()
    {
        this.delete();
    }

    delete()
    {
        if (this.loading)
        {
        // cant delete texture when still loading
        // setTimeout(this.delete.bind(this), 50);
            return;
        }

        this.deleted = true;
        this.width = 0;
        this.height = 0;
        this._cgl.profileData.profileTextureDelete++;
        this._cgl.gl.deleteTexture(this.tex);
        this.image = null;

        this.tex = null;
    }

    /**
     * @function isPowerOfTwo
     * @memberof Texture
     * @instance
     * @description return true if texture width and height are both power of two
     * @return {Boolean}
     */
    isPowerOfTwo()
    {
        return Texture.isPowerOfTwo(this.width) && Texture.isPowerOfTwo(this.height);
    }

    printInfo()
    {
        console.log(this.getInfo());
    }

    getInfoReadable()
    {
        const info = this.getInfo();
        let html = "";

        info.name = info.name.substr(0, info.name.indexOf("?rnd="));

        for (const i in info)
        {
            html += "* " + i + ":  **" + info[i] + "**\n";
        }

        return html;
    }

    getInfoOneLine()
    {
        let txt = "" + this.width + "x" + this.height;
        txt += " ";
        // if (this.textureType === CGL.Texture.TYPE_FLOAT) txt += " 32bit"; else txt += " 8bit";
        // if (this.textureType === CGL.Texture.TYPE_FLOAT) txt += " 32bit"; else txt += " 8bit";
        txt += this.pixelFormat;

        if (this.filter === CGL.Texture.FILTER_NEAREST) txt += " nearest";
        if (this.filter === CGL.Texture.FILTER_LINEAR) txt += " linear";
        if (this.filter === CGL.Texture.FILTER_MIPMAP) txt += " mipmap";

        if (this.wrap === CGL.Texture.WRAP_CLAMP_TO_EDGE) txt += " clamp";
        if (this.wrap === CGL.Texture.WRAP_REPEAT) txt += " repeat";
        if (this.wrap === CGL.Texture.WRAP_MIRRORED_REPEAT) txt += " repeatmir";

        this.shortInfoString = txt;

        return txt;
    }

    getInfoOneLineShort()
    {
        let txt = "" + this.width + "x" + this.height;
        // if (this.textureType === CGL.Texture.TYPE_FLOAT) txt += " 32bit"; else txt += " 8bit";
        txt += " ";
        txt += this.pixelFormat;

        this.shortInfoString = txt;

        return txt;
    }


    getInfo()
    {
        return Texture.getTexInfo(this);
    }


    _setFilter()
    {
        this._cgl.printError("before _setFilter");

        if (!this._fromData)
        {
            this._cgl.gl.pixelStorei(this._cgl.gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.unpackAlpha);
        }

        if (this.shadowMap)
        {
            this._cgl.gl.texParameteri(this._cgl.gl.TEXTURE_2D, this._cgl.gl.TEXTURE_COMPARE_MODE, this._cgl.gl.COMPARE_REF_TO_TEXTURE);
            this._cgl.gl.texParameteri(this._cgl.gl.TEXTURE_2D, this._cgl.gl.TEXTURE_COMPARE_FUNC, this._cgl.gl.LEQUAL);
        }

        if (this.textureType == Texture.TYPE_FLOAT && this.filter == Texture.FILTER_MIPMAP)
        {
            this.filter = Texture.FILTER_LINEAR;
            this._log.stack("texture: HDR and mipmap filtering at the same time is not possible");
        }

        if (this._cgl.glVersion == 1 && !this.isPowerOfTwo())
        {
            this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MAG_FILTER, this._cgl.gl.NEAREST);
            this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MIN_FILTER, this._cgl.gl.NEAREST);

            this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_S, this._cgl.gl.CLAMP_TO_EDGE);
            this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_T, this._cgl.gl.CLAMP_TO_EDGE);

            this.filter = Texture.FILTER_NEAREST;
            this.wrap = Texture.WRAP_CLAMP_TO_EDGE;
        }
        else
        {
            if (this.wrap == Texture.WRAP_CLAMP_TO_EDGE)
            {
                this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_S, this._cgl.gl.CLAMP_TO_EDGE);
                this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_T, this._cgl.gl.CLAMP_TO_EDGE);
            }
            else if (this.wrap == Texture.WRAP_REPEAT)
            {
                this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_S, this._cgl.gl.REPEAT);
                this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_T, this._cgl.gl.REPEAT);
            }
            else if (this.wrap == Texture.WRAP_MIRRORED_REPEAT)
            {
                this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_S, this._cgl.gl.MIRRORED_REPEAT);
                this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_WRAP_T, this._cgl.gl.MIRRORED_REPEAT);
            }

            if (this.filter == Texture.FILTER_NEAREST)
            {
                this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MAG_FILTER, this._cgl.gl.NEAREST);
                this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MIN_FILTER, this._cgl.gl.NEAREST);
            }
            else if (this.filter == Texture.FILTER_LINEAR)
            {
                this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MIN_FILTER, this._cgl.gl.LINEAR);
                this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MAG_FILTER, this._cgl.gl.LINEAR);
            }
            else if (this.filter == Texture.FILTER_MIPMAP)
            {
                this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MAG_FILTER, this._cgl.gl.LINEAR);
                this._cgl.gl.texParameteri(this.texTarget, this._cgl.gl.TEXTURE_MIN_FILTER, this._cgl.gl.LINEAR_MIPMAP_LINEAR);
            }
            else
            {
                this._log.log("unknown texture filter!", this.filter);
                throw new Error("unknown texture filter!" + this.filter);
            }

            if (this.anisotropic)
            {
                const ext = this._cgl.enableExtension("EXT_texture_filter_anisotropic");



                if (this._cgl.maxAnisotropic)
                {
                    const aniso = Math.min(this._cgl.maxAnisotropic, this.anisotropic);
                    this._cgl.gl.texParameterf(this._cgl.gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY_EXT, aniso);
                }
            }
        }
        this.getInfoOneLine();
        this._cgl.printError("_setFilter");
    }
}


























/**
 * @function load
 * @static
 * @memberof Texture
 * @description load an image from an url
 * @param {Context} cgl
 * @param {String} url
 * @param {Function} finishedCallback
 * @param {Object} settings
 * @return {Texture}
 */
Texture.load = function (cgl, url, finishedCallback, settings)
{
    if (!url) return finishedCallback({ "error": true });
    let loadingId = null;
    if (!cgl.patch.loading.existByName(url)) loadingId = cgl.patch.loading.start("cgl.texture", url);

    const texture = new Texture(cgl);
    texture.name = url;

    texture.image = new Image();
    texture.image.crossOrigin = "anonymous";
    texture.loading = true;

    if (settings && settings.hasOwnProperty("filter")) texture.filter = settings.filter;
    if (settings && settings.hasOwnProperty("flip")) texture.flip = settings.flip;
    if (settings && settings.hasOwnProperty("wrap")) texture.wrap = settings.wrap;
    if (settings && settings.hasOwnProperty("anisotropic")) texture.anisotropic = settings.anisotropic;
    if (settings && settings.hasOwnProperty("unpackAlpha")) texture.unpackAlpha = settings.unpackAlpha;
    if (settings && settings.hasOwnProperty("pixelFormat")) texture.pixelFormat = settings.pixelFormat;

    texture.image.onabort = texture.image.onerror = (e) =>
    {
        console.warn("[cgl.texture.load] error loading texture", url, e);
        texture.loading = false;
        if (loadingId) cgl.patch.loading.finished(loadingId);
        const error = { "error": true };
        if (finishedCallback) finishedCallback(error, texture);
    };

    texture.image.onload = function (e)
    {
        cgl.addNextFrameOnceCallback(() =>
        {
            texture.initTexture(texture.image);
            if (loadingId) cgl.patch.loading.finished(loadingId);
            texture.loading = false;

            if (finishedCallback) finishedCallback(null, texture);
        });
    };
    texture.image.src = url;

    return texture;
};






/**
 * @static
 * @function getTempTexture
 * @memberof Texture
 * @description returns the default temporary texture (grey diagonal stipes)
 * @param {Context} cgl
 * @return {Texture}
 */
Texture.getTempTexture = function (cgl)
{
    if (!cgl) console.error("[getTempTexture] no cgl!");
    if (!cgl.tempTexture) cgl.tempTexture = Texture.getTemporaryTexture(cgl, 256, Texture.FILTER_LINEAR, Texture.REPEAT);
    return cgl.tempTexture;
};

/**
 * @static
 * @function getErrorTexture
 * @memberof Texture
 * @description returns the default temporary texture (grey diagonal stipes)
 * @param {Context} cgl
 * @return {Texture}
 */
Texture.getErrorTexture = function (cgl)
{
    if (!cgl) console.error("[getTempTexture] no cgl!");
    if (!cgl.errorTexture) cgl.errorTexture = Texture.getTemporaryTexture(cgl, 256, Texture.FILTER_LINEAR, Texture.REPEAT, 1, 0.2, 0.2);
    return cgl.errorTexture;
};


/**
 * @function getEmptyTexture
 * @memberof Texture
 * @instance
 * @param cgl
 * @param fp
 * @description returns a reference to a small empty (transparent) texture
 * @return {Texture}
 */
Texture.getEmptyTexture = function (cgl, fp)
{
    if (fp) return Texture.getEmptyTextureFloat(cgl);
    if (!cgl) console.error("[getEmptyTexture] no cgl!");
    if (cgl.tempTextureEmpty) return cgl.tempTextureEmpty;

    let size = 8;

    cgl.tempTextureEmpty = new Texture(cgl, { "name": "emptyTexture" });
    const data = Texture.getDefaultTextureData("empty", size);

    cgl.tempTextureEmpty.initFromData(data, size, size, Texture.FILTER_NEAREST, Texture.WRAP_REPEAT);

    return cgl.tempTextureEmpty;
};

/**
 * @function getEmptyTextureFloat
 * @memberof Texture
 * @instance
 * @param cgl
 * @description returns a reference to a small empty (transparent) 32bit texture
 * @return {Texture}
 */
Texture.getEmptyTextureFloat = function (cgl)
{
    if (!cgl) console.error("[getEmptyTextureFloat] no cgl!");
    if (cgl.tempTextureEmptyFloat) return cgl.tempTextureEmptyFloat;

    cgl.tempTextureEmptyFloat = new Texture(cgl, { "name": "emptyTexture", "isFloatingPointTexture": true });
    const data = new Float32Array(8 * 8 * 4).fill(1);
    for (let i = 0; i < 8 * 8 * 4; i += 4) data[i + 3] = 0;

    cgl.tempTextureEmptyFloat.initFromData(data, 8, 8, Texture.FILTER_NEAREST, Texture.WRAP_REPEAT);

    return cgl.tempTextureEmptyFloat;
};


/**
 * @function getRandomTexture
 * @memberof Texture
 * @static
 * @param cgl
 * @description returns a reference to a random texture
 * @return {Texture}
 */
Texture.getRandomTexture = function (cgl)
{
    if (!cgl) console.error("[getRandomTexture] no cgl!");
    if (cgl.randomTexture) return cgl.randomTexture;

    const size = 256;
    const data = Texture.getDefaultTextureData("randomUInt", size);

    cgl.randomTexture = new Texture(cgl);
    cgl.randomTexture.initFromData(data, size, size, Texture.FILTER_NEAREST, Texture.WRAP_REPEAT);

    return cgl.randomTexture;
};

/**
 * @function getRandomFloatTexture
 * @memberof Texture
 * @static
 * @param cgl
 * @description returns a reference to a texture containing random numbers between -1 and 1
 * @return {Texture}
 */
Texture.getRandomFloatTexture = function (cgl)
{
    if (!cgl) console.error("[getRandomTexture] no cgl!");
    if (cgl.getRandomFloatTexture) return cgl.getRandomFloatTexture;

    const size = 256;
    const data = Texture.getDefaultTextureData("randomFloat", size);

    cgl.getRandomFloatTexture = new Texture(cgl, { "isFloatingPointTexture": true });
    cgl.getRandomFloatTexture.initFromData(data, size, size, Texture.FILTER_NEAREST, Texture.WRAP_REPEAT);

    return cgl.getRandomFloatTexture;
};

/**
 * @function getBlackTexture
 * @memberof Texture
 * @static
 * @param cgl
 * @description returns a reference to a black texture
 * @return {Texture}
 */
Texture.getBlackTexture = function (cgl)
{
    if (!cgl) this._log.error("[getBlackTexture] no cgl!");
    if (cgl.blackTexture) return cgl.blackTexture;

    const size = 8;
    const data = Texture.getDefaultTextureData("color", size, { "r": 0, "g": 0, "b": 0 });

    cgl.blackTexture = new Texture(cgl);
    cgl.blackTexture.initFromData(data, size, size, Texture.FILTER_NEAREST, Texture.WRAP_REPEAT);

    return cgl.blackTexture;
};


/**
 * @function getEmptyCubemapTexture
 * @memberof Texture
 * @static
 * @param cgl
 * @description returns an empty cubemap texture with rgba = [0, 0, 0, 0]
 * @return {Texture}
 */
Texture.getEmptyCubemapTexture = function (cgl)
{
    const faces = [
        cgl.gl.TEXTURE_CUBE_MAP_POSITIVE_X,
        cgl.gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
        cgl.gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
        cgl.gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
        cgl.gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
        cgl.gl.TEXTURE_CUBE_MAP_NEGATIVE_Z
    ];

    const tex = cgl.gl.createTexture();
    const target = cgl.gl.TEXTURE_CUBE_MAP;
    const filter = Texture.FILTER_NEAREST;
    const wrap = Texture.WRAP_CLAMP_TO_EDGE;
    const width = 8;
    const height = 8;

    cgl.profileData.profileTextureNew++;


    cgl.gl.bindTexture(target, tex);
    cgl.profileData.profileTextureResize++;

    for (let i = 0; i < 6; i += 1)
    {
        const data = new Uint8Array(8 * 8 * 4);

        cgl.gl.texImage2D(faces[i], 0, cgl.gl.RGBA, 8, 8, 0, cgl.gl.RGBA, cgl.gl.UNSIGNED_BYTE, data);
        cgl.gl.texParameteri(target, cgl.gl.TEXTURE_MAG_FILTER, cgl.gl.NEAREST);
        cgl.gl.texParameteri(target, cgl.gl.TEXTURE_MIN_FILTER, cgl.gl.NEAREST);

        cgl.gl.texParameteri(target, cgl.gl.TEXTURE_WRAP_S, cgl.gl.CLAMP_TO_EDGE);
        cgl.gl.texParameteri(target, cgl.gl.TEXTURE_WRAP_T, cgl.gl.CLAMP_TO_EDGE);
    }


    cgl.gl.bindTexture(target, null);

    return {
        "id": CABLES.uuid(),
        "tex": tex,
        "cubemap": tex,
        "width": width,
        "height": height,
        "filter": filter,
        "wrap": wrap,
        "unpackAlpha": true,
        "flip": true,
        "_fromData": true,
        "name": "emptyCubemapTexture",
        "anisotropic": 0,
    };
};


Texture.getTempGradientTexture = function (cgl) // deprecated...
{
    if (!cgl) console.error("[getTempGradientTexture] no cgl!");
    return Texture.getTempTexture(cgl);
};

Texture.getTemporaryTexture = function (cgl, size, filter, wrap, r, g, b)
{
    const data = Texture.getDefaultTextureData("stripes", 256, { "r": r, "g": g, "b": b });
    const temptex = new Texture(cgl);
    temptex.initFromData(data, size, size, filter, wrap);
    return temptex;
};

/**
 * @static
 * @function createFromImage
 * @memberof Texture
 * @description create texturem from image data (e.g. image or canvas)
 * @param {Context} cgl
 * @param {Object} img image
 * @param {Object} options
 */
Texture.createFromImage = function (cgl, img, options)
{
    options = options || {};
    const texture = new Texture(cgl, options);
    texture.flip = false;
    texture.image = img;
    texture.width = img.videoWidth || img.width || 8;
    texture.height = img.videoHeight || img.height || 8;
    if (options.hasOwnProperty("wrap"))texture.wrap = options.wrap;

    texture.initTexture(img, options.filter);

    return texture;
};

// deprecated!
Texture.fromImage = function (cgl, img, filter, wrap)
{
    console.error("deprecated texture from image...");

    const texture = new Texture(cgl);
    texture.flip = false;
    if (filter) texture.filter = filter;
    if (wrap) texture.wrap = wrap;
    texture.image = img;
    texture.initTexture(img);
    return texture;
};

/**
 * @static
 * @function isPowerOfTwo
 * @memberof Texture
 * @description returns true if x is power of two
 * @param {Number} x
 * @return {Boolean}
 */
Texture.isPowerOfTwo = function (x)
{
    return x == 1 || x == 2 || x == 4 || x == 8 || x == 16 || x == 32 || x == 64 || x == 128 || x == 256 || x == 512 || x == 1024 || x == 2048 || x == 4096 || x == 8192 || x == 16384;
};

Texture.getTexInfo = function (tex)
{
    const obj = {};

    obj.name = tex.name;
    obj["power of two"] = tex.isPowerOfTwo();
    obj.size = tex.width + " x " + tex.height;

    let targetString = tex.texTarget;
    if (tex.texTarget == tex._cgl.gl.TEXTURE_2D) targetString = "TEXTURE_2D";
    obj.target = targetString;

    obj.unpackAlpha = tex.unpackAlpha;

    if (tex.cubemap)obj.cubemap = true;

    if (tex.textureType == Texture.TYPE_FLOAT) obj.textureType = "TYPE_FLOAT";
    if (tex.textureType == Texture.TYPE_HALF_FLOAT) obj.textureType = "TYPE_HALF_FLOAT";
    else if (tex.textureType == Texture.TYPE_DEPTH) obj.textureType = "TYPE_DEPTH";
    else if (tex.textureType == Texture.TYPE_DEFAULT) obj.textureType = "TYPE_DEFAULT";
    else obj.textureType = "UNKNOWN " + this.textureType;

    if (tex.wrap == Texture.WRAP_CLAMP_TO_EDGE) obj.wrap = "CLAMP_TO_EDGE";
    else if (tex.wrap == Texture.WRAP_REPEAT) obj.wrap = "WRAP_REPEAT";
    else if (tex.wrap == Texture.WRAP_MIRRORED_REPEAT) obj.wrap = "WRAP_MIRRORED_REPEAT";
    else obj.wrap = "UNKNOWN";

    if (tex.filter == Texture.FILTER_NEAREST) obj.filter = "FILTER_NEAREST";
    else if (tex.filter == Texture.FILTER_LINEAR) obj.filter = "FILTER_LINEAR";
    else if (tex.filter == Texture.FILTER_MIPMAP) obj.filter = "FILTER_MIPMAP";
    else obj.filter = "UNKNOWN";

    obj.pixelFormat = tex.pixelFormat || "unknown";

    return obj;
};

Texture.setUpGlPixelFormat = function (cgl, pixelFormatStr)
{
    const o = {};

    if (!pixelFormatStr)
    {
        cgl._log.error("no pixelformatstr!");
        cgl._log.log(new Error());
        pixelFormatStr = Texture.PFORMATSTR_RGBA8UB;
    }

    o.pixelFormatBase = pixelFormatStr;
    o.pixelFormat = pixelFormatStr;
    o.glDataType = cgl.gl.UNSIGNED_BYTE;
    o.glInternalFormat = cgl.gl.RGBA8;
    o.glDataFormat = cgl.gl.RGBA;

    let floatDatatype = cgl.gl.FLOAT;

    if (cgl.glUseHalfFloatTex)
    {
        if (pixelFormatStr == Texture.PFORMATSTR_RGBA32F) pixelFormatStr = Texture.PFORMATSTR_RGBA16F;
        if (pixelFormatStr == Texture.PFORMATSTR_RG32F) pixelFormatStr = Texture.PFORMATSTR_RG16F;
        if (pixelFormatStr == Texture.PFORMATSTR_R32F) pixelFormatStr = Texture.PFORMATSTR_R16F;
    }

    if (pixelFormatStr.contains("16bit"))
    {
        if (cgl.glVersion == 2)
        {
            // cgl.enableExtension("OES_texture_half_float");
            const hasExt = cgl.enableExtension("EXT_color_buffer_half_float");

            if (!hasExt)
            {
                console.warn("no 16bit extension, fallback to 32bit", pixelFormatStr);
                // fallback to 32 bit?
                if (pixelFormatStr == Texture.PFORMATSTR_RGBA16F) pixelFormatStr = Texture.PFORMATSTR_RGBA32F;
                if (pixelFormatStr == Texture.PFORMATSTR_RGB16F) pixelFormatStr = Texture.PFORMATSTR_RGB32F;
                if (pixelFormatStr == Texture.PFORMATSTR_RG16F) pixelFormatStr = Texture.PFORMATSTR_RG32F;
                if (pixelFormatStr == Texture.PFORMATSTR_R16F) pixelFormatStr = Texture.PFORMATSTR_R32F;
            }
            else
            {
                floatDatatype = cgl.gl.HALF_FLOAT;
            }
        }
    }

    if (cgl.glVersion == 1)
    {
        o.glInternalFormat = cgl.gl.RGBA;

        if (pixelFormatStr == Texture.PFORMATSTR_RGBA16F || pixelFormatStr == Texture.PFORMATSTR_RG16F || pixelFormatStr == Texture.PFORMATSTR_R16F)
        {
            const ext = cgl.enableExtension("OES_texture_half_float");
            if (!ext) throw new Error("no half float texture extension");

            floatDatatype = ext.HALF_FLOAT_OES;
        }
    }


    if (pixelFormatStr == Texture.PFORMATSTR_RGBA8UB)
    {
    }
    else if (pixelFormatStr == Texture.PFORMATSTR_RGB565)
    {
        o.glInternalFormat = cgl.gl.RGB565;
        o.glDataFormat = cgl.gl.RGB;
    }
    else if (pixelFormatStr == Texture.PFORMATSTR_R8UB)
    {
        o.glInternalFormat = cgl.gl.R8;
        o.glDataFormat = cgl.gl.RED;
    }
    else if (pixelFormatStr == Texture.PFORMATSTR_RG8UB)
    {
        o.glInternalFormat = cgl.gl.RG8;
        o.glDataFormat = cgl.gl.RG;
    }
    else if (pixelFormatStr == Texture.PFORMATSTR_RGB8UB)
    {
        o.glInternalFormat = cgl.gl.RGB8;
        o.glDataFormat = cgl.gl.RGB;
    }
    else if (pixelFormatStr == Texture.PFORMATSTR_SRGBA8)
    {
        o.glInternalFormat = cgl.gl.SRGB8_ALPHA8;
    }

    else if (pixelFormatStr == Texture.PFORMATSTR_R32F)
    {
        o.glInternalFormat = cgl.gl.R32F;
        o.glDataFormat = cgl.gl.RED;
        o.glDataType = floatDatatype;
    }
    else if (pixelFormatStr == Texture.PFORMATSTR_R16F)
    {
        o.glInternalFormat = cgl.gl.R16F;
        o.glDataType = floatDatatype;
        o.glDataFormat = cgl.gl.RED;
    }
    else if (pixelFormatStr == Texture.PFORMATSTR_RG16F)
    {
        o.glInternalFormat = cgl.gl.RG16F;
        o.glDataType = floatDatatype;
        o.glDataFormat = cgl.gl.RG;
    }
    else if (pixelFormatStr == Texture.PFORMATSTR_RGBA16F)
    {
        if (cgl.glVersion == 1) o.glInternalFormat = cgl.gl.RGBA;
        else o.glInternalFormat = cgl.gl.RGBA16F;
        o.glDataType = floatDatatype;
    }
    else if (pixelFormatStr == Texture.PFORMATSTR_R11FG11FB10F)
    {
        o.glInternalFormat = cgl.gl.R11F_G11F_B10F;
        o.glDataType = floatDatatype;
        o.glDataFormat = cgl.gl.RGB;
    }
    else if (pixelFormatStr == Texture.PFORMATSTR_RGBA32F)
    {
        if (cgl.glVersion == 1) o.glInternalFormat = cgl.gl.RGBA;
        else o.glInternalFormat = cgl.gl.RGBA32F;
        o.glDataType = floatDatatype;
    }
    else if (pixelFormatStr == Texture.PFORMATSTR_DEPTH)
    {
        if (cgl.glVersion == 1)
        {
            o.glInternalFormat = cgl.gl.DEPTH_COMPONENT;
            o.glDataType = cgl.gl.UNSIGNED_SHORT;
            o.glDataFormat = cgl.gl.DEPTH_COMPONENT;
        }
        else
        {
            o.glInternalFormat = cgl.gl.DEPTH_COMPONENT32F;
            o.glDataType = cgl.gl.FLOAT;
            o.glDataFormat = cgl.gl.DEPTH_COMPONENT;
        }
    }
    else
    {
        console.log("unknown pixelformat ", pixelFormatStr);
    }

    /// //////

    if (pixelFormatStr.contains("32bit") || pixelFormatStr == Texture.PFORMATSTR_R11FG11FB10F)
    {
        if (cgl.glVersion == 2) cgl.enableExtension("EXT_color_buffer_float");
        if (cgl.glVersion == 2) cgl.enableExtension("EXT_float_blend");

        cgl.enableExtension("OES_texture_float_linear"); // yes, i am sure, this is a webgl 1 and 2 ext
    }


    o.numColorChannels = Texture.getPixelFormatNumChannels(pixelFormatStr);


    if (!o.glDataType || !o.glInternalFormat || !o.glDataFormat) console.log("pixelformat wrong ?!", pixelFormatStr, o.glDataType, o.glInternalFormat, o.glDataFormat, this);

    return o;
};



Texture.getPixelFormatNumChannels =
    (pxlFrmtStr) =>
    {
        if (pxlFrmtStr.startsWith("RGBA")) return 4;
        if (pxlFrmtStr.startsWith("RGB")) return 3;
        if (pxlFrmtStr.startsWith("RG")) return 2;
        return 1;
    };

Texture.isPixelFormatFloat =
    (pxlFrmtStr) =>
    {
        return (pxlFrmtStr || "").contains("float");
    };

Texture.isPixelFormatHalfFloat =
    (pxlFrmtStr) =>
    {
        return (pxlFrmtStr || "").contains("float") && (pxlFrmtStr || "").contains("16bit");
    };






;// CONCATENATED MODULE: ./src/core/cg/cg_boundingbox.js


/**
 * bounding box
 *
 * @namespace external:CGL
 * @param {Geometry} geometry or bounding box
 */
class BoundingBox
{
    constructor(geom)
    {
        this._init();
        this._first = true;
        this._wireMesh = null;

        if (geom) this.apply(geom);
    }

    _init()
    {
        this._max = [-0, -0, -0];
        this._min = [0, 0, 0];
        this._center = [0, 0, 0];
        this._size = [0, 0, 0];
        this._maxAxis = 0.0;
        this._first = true;
    }

    /**
     * get biggest number of maxX,maxY,maxZ
     * @type {Number}
     */
    get maxAxis() { return this._maxAxis || 1; }

    /**
     * size of bounding box
     * @type {vec3}
     */
    get size() { return this._size; }

    /**
     * center of bounding box
     * @type {vec3}
     */
    get center() { return this._center; }

    /**
     * center x
     * @type {Number}
     */
    get x() { return this._center[0]; }

    /**
     * center y
     * @type {Number}
     */
    get y() { return this._center[1]; }

    /**
     * center z
     * @type {Number}
     */
    get z() { return this._center[2]; }


    /**
     * minimum x
     * @type {Number}
     */
    get minX() { return this._min[0]; }

    /**
     * minimum y
     * @type {Number}
     */
    get minY() { return this._min[1]; }

    /**
     * minimum z
     * @type {Number}
     */
    get minZ() { return this._min[2]; }

    /**
     * maximum x
     * @type {Number}
     */
    get maxX() { return this._max[0]; }

    /**
     * maximum y
     * @type {Number}
     */
    get maxY() { return this._max[1]; }

    /**
     * maximum z
     * @type {Number}
     */
    get maxZ() { return this._max[2]; }


    apply(geom, mat)
    {
        if (!geom)
        {
            // console.warn("[boundingbox] no geom/vertices", geom);
            return;
        }

        if (geom instanceof BoundingBox)
        {
            const bb = geom;

            this.applyPos(bb.maxX, bb.maxY, bb.maxZ);
            this.applyPos(bb.minX, bb.minY, bb.minZ);
        }
        else
        {
            for (let i = 0; i < geom.vertices.length; i += 3)
                this.applyPos(geom.vertices[i], geom.vertices[i + 1], geom.vertices[i + 2]);
        }
        this.calcCenterSize();
    }

    /**
     * returns a copy of the bounding box
     * @function copy
     * @memberof BoundingBox
     * @instance
     */
    copy()
    {
        return new BoundingBox(this);
    }

    get changed()
    {
        return !(this._max[0] == -Number.MAX_VALUE && this._max[1] == -Number.MAX_VALUE && this._max[2] == -Number.MAX_VALUE);
    }

    applyPos(x, y, z)
    {
        if (x == Number.MAX_VALUE || x == -Number.MAX_VALUE ||
            y == Number.MAX_VALUE || y == -Number.MAX_VALUE ||
            z == Number.MAX_VALUE || z == -Number.MAX_VALUE) return;

        if (!CABLES.UTILS.isNumeric(x) || !CABLES.UTILS.isNumeric(y) || !CABLES.UTILS.isNumeric(z)) return;

        if (this._first)
        {
            this._max[0] = x;
            this._max[1] = y;
            this._max[2] = z;

            this._min[0] = x;
            this._min[1] = y;
            this._min[2] = z;
            this._first = false;
            return;
        }

        this._max[0] = Math.max(this._max[0], x);
        this._max[1] = Math.max(this._max[1], y);
        this._max[2] = Math.max(this._max[2], z);

        this._min[0] = Math.min(this._min[0], x);
        this._min[1] = Math.min(this._min[1], y);
        this._min[2] = Math.min(this._min[2], z);
    }

    calcCenterSize()
    {
        if (this._first) return;


        this._size[0] = this._max[0] - this._min[0];
        this._size[1] = this._max[1] - this._min[1];
        this._size[2] = this._max[2] - this._min[2];

        this._center[0] = (this._min[0] + this._max[0]) / 2;
        this._center[1] = (this._min[1] + this._max[1]) / 2;
        this._center[2] = (this._min[2] + this._max[2]) / 2;

        this._maxAxis = Math.max(this._size[2], Math.max(this._size[0], this._size[1]));
    }

    mulMat4(m)
    {
        if (this._first)
        {
            this._max[0] = 0;
            this._max[1] = 0;
            this._max[2] = 0;

            this._min[0] = 0;
            this._min[1] = 0;
            this._min[2] = 0;
            this._first = false;
        }
        vec3.transformMat4(this._max, this._max, m);
        vec3.transformMat4(this._min, this._min, m);
        this.calcCenterSize();
    }

    render(cgl, shader, op)
    {
        if (!this._wireMesh) this._wireMesh = new CGL.WireCube(cgl);

        cgl.pushModelMatrix();
        mat4.translate(cgl.mMatrix, cgl.mMatrix, this._center);

        if (CABLES.UI && op)
        {
            CABLES.UI.OverlayMeshes.drawCube(op, this._size[0] / 2, this._size[1] / 2, this._size[2] / 2);
        }

        cgl.popModelMatrix();
    }
}

;// CONCATENATED MODULE: ./src/core/cg/cg_geom.js
// import { vec2, vec3 } from "gl-matrix";




/**
 * a geometry contains all information about a mesh, vertices, texturecoordinates etc. etc.
 * @namespace external:CGL#Geometry
 * @param {String} name
 * @class
 * @example
 * // create a triangle with all attributes
 * const geom=new Geometry("triangle"),
 *
 * geom.vertices = [
 *      0.0,           sizeH.get(),  0.0,
 *     -sizeW.get(),  -sizeH.get(),  0.0,
 *      sizeW.get(),  -sizeH.get(),  0.0 ];
 *
 * geom.vertexNormals = [
 *      0.0,  0.0,  1.0,
 *      0.0,  0.0,  1.0,
 *      0.0,  0.0,  1.0 ];
 *
 * geom.tangents = [
 *     1,0,0,
 *     1,0,0,
 *     1,0,0 ];
 *
 * geom.biTangents = [
 *     0,1,0,
 *     0,1,0,
 *     0,1,0 ];
 *
 * geom.texCoords = [
 *      0.5,  0.0,
 *      1.0,  1.0,
 *      0.0,  1.0, ];
 *
 * geom.verticesIndices = [
 *     0, 1, 2 ];
 *
 */
const Geometry = function (name)
{
    this.name = name || "unknown";
    this._log = new Logger("cgl_geometry");

    this.faceVertCount = 3;
    this.glPrimitive = null;
    this._attributes = {};

    this._vertices = [];
    this.verticesIndices = [];

    this.isGeometry = true;

    this.morphTargets = [];

    Object.defineProperty(this, "vertices", {
        get()
        {
            return this._vertices;
        },
        set(v)
        {
            this.setVertices(v);
        },
    });

    Object.defineProperty(this, "texCoords", {
        get()
        {
            const att = this.getAttribute("texCoords");
            if (!att) return [];
            return att.data;
        },
        set(v)
        {
            this.setAttribute("texCoords", v, 2);
        },
    });

    Object.defineProperty(this, "vertexNormals", {
        get()
        {
            const att = this.getAttribute("vertexNormals");
            if (!att) return [];
            return att.data;
        },
        set(v)
        {
            this.setAttribute("vertexNormals", v, 3);
        },
    });

    Object.defineProperty(this, "tangents", {
        get()
        {
            const att = this.getAttribute("tangents");
            if (!att) return [];
            return att.data;
        },
        set(v)
        {
            this.setAttribute("tangents", v, 3);
        },
    });

    Object.defineProperty(this, "biTangents", {
        get()
        {
            const att = this.getAttribute("biTangents");
            if (!att) return [];
            return att.data;
        },
        set(v)
        {
            this.setAttribute("biTangents", v, 3);
        },
    });

    Object.defineProperty(this, "vertexColors", {
        get()
        {
            const att = this.getAttribute("vertexColors");
            if (!att) return [];
            return att.data;
        },
        set(v)
        {
            this.setAttribute("vertexColors", v, 4);
        },
    });
};

/**
 * @function clear
 * @memberof Geometry
 * @instance
 * @description clear all buffers/set them to length 0
 */
Geometry.prototype.clear = function ()
{
    this._vertices = new Float32Array([]);
    this.verticesIndices = [];
    this.texCoords = new Float32Array([]);
    this.vertexNormals = new Float32Array([]);
    this.tangents = [];
    this.biTangents = [];
    this._attributes = {};
};



/**
 * @function getAttributes
   @memberof Geometry
 * @instance
 * @return {Array<Object>} returns array of attribute objects
 */
Geometry.prototype.getAttributes = function ()
{
    return this._attributes;
};

/**
 * @function getAttribute
 * @memberof Geometry
 * @instance
 * @param {String} name
 * @return {Object}
 */
Geometry.prototype.getAttribute = function (name)
{
    for (const i in this._attributes)
    {
        if (this._attributes[i].name == name) return this._attributes[i];
    }
    return null;
};

/**
 * @function setAttribute
 * @description create an attribute
 * @memberof Geometry
 * @instance
 * @param {String} name
 * @param {Array} arr
 * @param {Number} itemSize
 */
Geometry.prototype.setAttribute = function (name, arr, itemSize)
{
    let attrType = "";
    if (!itemSize || itemSize > 4)
    {
        console.log("itemsize wrong?", itemSize, name);
        this._log.stack("itemsize");

        itemSize = 3;
    }

    if (itemSize == 1) attrType = "float";
    else if (itemSize == 2) attrType = "vec2";
    else if (itemSize == 3) attrType = "vec3";
    else if (itemSize == 4) attrType = "vec4";


    const attr = {
        "name": name,
        "data": arr,
        "itemSize": itemSize,
        "type": attrType,
    };

    this._attributes[name] = attr;
};

Geometry.prototype.copyAttribute = function (name, newgeom)
{
    const attr = this.getAttribute(name);
    newgeom.setAttribute(name, new Float32Array(attr.data), attr.itemSize);
};


/**
 * @function setVertices
 * @memberof Geometry
 * @instance
 * @description set vertices
 * @param {Array|Float32Array} arr [x,y,z,x,y,z,...]
 */
Geometry.prototype.setVertices = function (arr)
{
    if (arr instanceof Float32Array) this._vertices = arr;
    else this._vertices = new Float32Array(arr);
};

/**
 * @function setTexCoords
 * @memberof Geometry
 * @instance
 * @description set texcoords
 * @param {Array|Float32Array} arr [u,v,u,v,...]
 */
Geometry.prototype.setTexCoords = function (arr)
{
    if (arr instanceof Float32Array) this.texCoords = arr;
    else this.texCoords = new Float32Array(arr);
};

// Geometry.prototype.testIndices = function ()
// {
//     var foundError = false;
//     for (var i = 0; i < this.verticesIndices.length; i++)
//     {
//         if (this.verticesIndices[i * 3 + 0] >= this._vertices.length / 3 || this.verticesIndices[i * 3 + 1] >= this._vertices.length / 3 || this.verticesIndices[i * 3 + 2] >= this._vertices.length / 3)
//         {
//             foundError = true;
//             console.log("index error!");
//         }
//     }
// };

// deprecated
Geometry.prototype.calcNormals = function (smooth)
{
    const options = { "smooth": smooth };
    this.calculateNormals(options);
};

/**
 * @function flipNormals
 * @memberof Geometry
 * @param x
 * @param y
 * @param z
 * @description flip normals
 */
Geometry.prototype.flipNormals = function (x, y, z)
{
    let vec = vec3.create();

    if (x == undefined)x = 1;
    if (y == undefined)y = 1;
    if (z == undefined)z = 1;


    for (let i = 0; i < this.vertexNormals.length; i += 3)
    {
        vec3.set(vec,
            this.vertexNormals[i + 0],
            this.vertexNormals[i + 1],
            this.vertexNormals[i + 2]);

        vec[0] *= -x;
        vec[1] *= -y;
        vec[2] *= -z;

        vec3.normalize(vec, vec);

        this.vertexNormals[i + 0] = vec[0];
        this.vertexNormals[i + 1] = vec[1];
        this.vertexNormals[i + 2] = vec[2];
    }
};

Geometry.prototype.getNumTriangles = function ()
{
    if (this.verticesIndices && this.verticesIndices.length) return this.verticesIndices.length / 3;
    return this.vertices.length / 3;
};


/**
 * @function flipVertDir
 * @memberof Geometry
 * @description flip order of vertices in geom faces
 */
Geometry.prototype.flipVertDir = function ()
{
    const newInd = [];
    newInd.length = this.verticesIndices.length;
    for (let i = 0; i < this.verticesIndices.length; i += 3)
    {
        newInd[i] = this.verticesIndices[i + 2];
        newInd[i + 1] = this.verticesIndices[i + 1];
        newInd[i + 2] = this.verticesIndices[i];
    }
    this.verticesIndices = newInd;
};


Geometry.prototype.setPointVertices = function (verts)
{
    if (verts.length % 3 !== 0)
    {
        this._log.error("SetPointVertices: Array must be multiple of three.");
        return;
    }

    if (!(verts instanceof Float32Array)) this.vertices = new Float32Array(verts);
    else this.vertices = verts;

    if (!(this.texCoords instanceof Float32Array)) this.texCoords = new Float32Array((verts.length / 3) * 2);

    // this.texCoords.length=verts.length/3*2;
    this.verticesIndices.length = verts.length / 3;
    // this.verticesIndices=[];

    for (let i = 0; i < verts.length / 3; i++)
    {
        this.verticesIndices[i] = i;
        this.texCoords[i * 2] = 0;
        this.texCoords[i * 2 + 1] = 0;
    }
};

/**
 * merge a different geometry into the this geometry
 * @function merge
 * @param {Geometry} geom
 * @memberof Geometry
 * @instance
 */
Geometry.prototype.merge = function (geom)
{
    if (!geom) return;

    if (this.isIndexed() != geom.isIndexed())
    {
        if (this.isIndexed())
        {
            this.unIndex(false, true);
        }
        if (geom.isIndexed())
        {
            const g = geom.copy();
            g.unIndex(false, true);
            geom = g;
        }
    }

    const oldIndizesLength = this.verticesIndices.length;
    const vertLength = this._vertices.length / 3;

    this.verticesIndices.length += geom.verticesIndices.length;
    for (let i = 0; i < geom.verticesIndices.length; i++)
        this.verticesIndices[oldIndizesLength + i] = geom.verticesIndices[i] + vertLength;

    this.vertices = UTILS.float32Concat(this._vertices, geom.vertices);
    this.texCoords = UTILS.float32Concat(this.texCoords, geom.texCoords);
    this.vertexNormals = UTILS.float32Concat(this.vertexNormals, geom.vertexNormals);
    this.tangents = UTILS.float32Concat(this.tangents, geom.tangents);
    this.biTangents = UTILS.float32Concat(this.biTangents, geom.biTangents);
};

/**
 *   a copy of the geometry
 * @function copy
 * @memberof Geometry
 * @instance
 */
Geometry.prototype.copy = function ()
{
    const geom = new Geometry(this.name + " copy");
    geom.faceVertCount = this.faceVertCount;
    geom.glPrimitive = this.glPrimitive;

    geom.setVertices(this._vertices.slice(0));

    if (this.verticesIndices)
    {
        geom.verticesIndices.length = this.verticesIndices.length;
        for (let i = 0; i < this.verticesIndices.length; i++) geom.verticesIndices[i] = this.verticesIndices[i];
    }

    for (let i in this._attributes) this.copyAttribute(i, geom);

    geom.morphTargets.length = this.morphTargets.length;
    for (let i = 0; i < this.morphTargets.length; i++) geom.morphTargets[i] = this.morphTargets[i];

    return geom;
};

/**
 * Calculaten normals
 * @function calculateNormals
 * @memberof Geometry
 * @param options
 * @instance
 */
Geometry.prototype.calculateNormals = function (options)
{
    // todo: should check angle of normals to get edges    https://community.khronos.org/t/calculating-accurate-vertex-normals/28152
    options = options || {};
    if (options.smooth === false) this.unIndex();

    const u = vec3.create();
    const v = vec3.create();
    const n = vec3.create();

    function calcNormal(triangle)
    {
        vec3.subtract(u, triangle[0], triangle[1]);
        vec3.subtract(v, triangle[0], triangle[2]);
        vec3.cross(n, u, v);
        vec3.normalize(n, n);

        if (options && options.forceZUp)
        {
            if (n[2] < 0)
            {
                n[0] *= -1;
                n[1] *= -1;
                n[2] *= -1;
            }
        }
        return n;
    }

    this.getVertexVec = function (which)
    {
        const vec = [0, 0, 0];
        vec[0] = this.vertices[which * 3 + 0];
        vec[1] = this.vertices[which * 3 + 1];
        vec[2] = this.vertices[which * 3 + 2];
        return vec;
    };

    if (!(this.vertexNormals instanceof Float32Array) || this.vertexNormals.length != this.vertices.length) this.vertexNormals = new Float32Array(this.vertices.length);

    for (let i = 0; i < this.vertices.length; i++)
    {
        this.vertexNormals[i] = 0;
    }

    if (!this.isIndexed())
    {
        const norms = [];
        for (let i = 0; i < this.vertices.length; i += 9)
        {
            const triangle = [[this.vertices[i + 0], this.vertices[i + 1], this.vertices[i + 2]], [this.vertices[i + 3], this.vertices[i + 4], this.vertices[i + 5]], [this.vertices[i + 6], this.vertices[i + 7], this.vertices[i + 8]]];
            const nn = calcNormal(triangle);
            norms.push(nn[0], nn[1], nn[2], nn[0], nn[1], nn[2], nn[0], nn[1], nn[2]);
        }
        this.vertexNormals = norms;
    }
    else
    {
        const faceNormals = [];

        faceNormals.length = Math.floor(this.verticesIndices.length / 3);

        for (let i = 0; i < this.verticesIndices.length; i += 3)
        {
            const triangle = [this.getVertexVec(this.verticesIndices[i + 0]), this.getVertexVec(this.verticesIndices[i + 1]), this.getVertexVec(this.verticesIndices[i + 2])];

            faceNormals[i / 3] = calcNormal(triangle);

            this.vertexNormals[this.verticesIndices[i + 0] * 3 + 0] += faceNormals[i / 3][0];
            this.vertexNormals[this.verticesIndices[i + 0] * 3 + 1] += faceNormals[i / 3][1];
            this.vertexNormals[this.verticesIndices[i + 0] * 3 + 2] += faceNormals[i / 3][2];

            this.vertexNormals[this.verticesIndices[i + 1] * 3 + 0] += faceNormals[i / 3][0];
            this.vertexNormals[this.verticesIndices[i + 1] * 3 + 1] += faceNormals[i / 3][1];
            this.vertexNormals[this.verticesIndices[i + 1] * 3 + 2] += faceNormals[i / 3][2];

            this.vertexNormals[this.verticesIndices[i + 2] * 3 + 0] += faceNormals[i / 3][0];
            this.vertexNormals[this.verticesIndices[i + 2] * 3 + 1] += faceNormals[i / 3][1];
            this.vertexNormals[this.verticesIndices[i + 2] * 3 + 2] += faceNormals[i / 3][2];
        }


        for (let i = 0; i < this.verticesIndices.length; i += 3) // faces
        {
            for (let k = 0; k < 3; k++) // triangles
            {
                const vv = [this.vertexNormals[this.verticesIndices[i + k] * 3 + 0], this.vertexNormals[this.verticesIndices[i + k] * 3 + 1], this.vertexNormals[this.verticesIndices[i + k] * 3 + 2]];
                vec3.normalize(vv, vv);
                this.vertexNormals[this.verticesIndices[i + k] * 3 + 0] = vv[0];
                this.vertexNormals[this.verticesIndices[i + k] * 3 + 1] = vv[1];
                this.vertexNormals[this.verticesIndices[i + k] * 3 + 2] = vv[2];
            }
        }
    }
};

/**
 * Calculates tangents & bitangents with the help of uv-coordinates. Adapted from
 * Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”.
 * Terathon Software 3D Graphics Library.
 * https://fenix.tecnico.ulisboa.pt/downloadFile/845043405449073/Tangent%20Space%20Calculation.pdf
 *
 * @function calcTangentsBitangents
 * @memberof Geometry
 * @instance
 */
Geometry.prototype.calcTangentsBitangents = function ()
{
    if (!this.vertices.length)
    {
        // this._log.error("Cannot calculate tangents/bitangents without vertices.");
        return;
    }
    if (!this.vertexNormals.length)
    {
        // this._log.error("Cannot calculate tangents/bitangents without normals.");
        return;
    }
    if (!this.texCoords.length)
    {
        // console.warn("No texcoords. Replacing with default values [0, 0].");
        const texCoordLength = (this.vertices.length / 3) * 2;
        this.texCoords = new Float32Array(texCoordLength);
        for (let i = 0; i < texCoordLength; i += 1) this.texCoords[i] = 0;
    }
    if (!this.verticesIndices || !this.verticesIndices.length)
    {
        // this._log.error("Cannot calculate tangents/bitangents without vertex indices.");
        return;
    }
    // this code assumes that we have three indices per triangle
    if (this.verticesIndices.length % 3 !== 0)
    {
        this._log.error("Vertex indices mismatch!");
        return;
    }

    const triangleCount = this.verticesIndices.length / 3;
    const vertexCount = this.vertices.length / 3;

    this.tangents = new Float32Array(this.vertexNormals.length);
    this.biTangents = new Float32Array(this.vertexNormals.length);

    // temporary buffers
    const tempVertices = [];
    tempVertices.length = vertexCount * 2;
    const v1 = vec3.create();
    const v2 = vec3.create();
    const v3 = vec3.create();

    const w1 = vec2.create();
    const w2 = vec2.create();
    const w3 = vec2.create();

    const sdir = vec3.create();
    const tdir = vec3.create();

    // for details on calculation, see article referenced above
    for (let tri = 0; tri < triangleCount; tri += 1)
    {
        // indices of the three vertices for a triangle
        const i1 = this.verticesIndices[tri * 3];
        const i2 = this.verticesIndices[tri * 3 + 1];
        const i3 = this.verticesIndices[tri * 3 + 2];

        // vertex position as vec3
        vec3.set(v1, this.vertices[i1 * 3], this.vertices[i1 * 3 + 1], this.vertices[i1 * 3 + 2]);
        vec3.set(v2, this.vertices[i2 * 3], this.vertices[i2 * 3 + 1], this.vertices[i2 * 3 + 2]);
        vec3.set(v3, this.vertices[i3 * 3], this.vertices[i3 * 3 + 1], this.vertices[i3 * 3 + 2]);

        // texture coordinate as vec2
        vec2.set(w1, this.texCoords[i1 * 2], this.texCoords[i1 * 2 + 1]);
        vec2.set(w2, this.texCoords[i2 * 2], this.texCoords[i2 * 2 + 1]);
        vec2.set(w3, this.texCoords[i3 * 2], this.texCoords[i3 * 2 + 1]);

        const x1 = v2[0] - v1[0];
        const x2 = v3[0] - v1[0];
        const y1 = v2[1] - v1[1];
        const y2 = v3[1] - v1[1];
        const z1 = v2[2] - v1[2];
        const z2 = v3[2] - v1[2];

        const s1 = w2[0] - w1[0];
        const s2 = w3[0] - w1[0];
        const t1 = w2[1] - w1[1];
        const t2 = w3[1] - w1[1];

        const r = 1.0 / (s1 * t2 - s2 * t1);

        vec3.set(sdir, (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
        vec3.set(tdir, (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);

        tempVertices[i1] = sdir;
        tempVertices[i2] = sdir;
        tempVertices[i3] = sdir;

        tempVertices[i1 + vertexCount] = tdir;
        tempVertices[i2 + vertexCount] = tdir;
        tempVertices[i3 + vertexCount] = tdir;
    }

    const normal = vec3.create();
    const tempVert = vec3.create();
    const tan = vec3.create();
    const bitan = vec3.create();
    const temp1 = vec3.create();
    const temp2 = vec3.create();
    const crossPd = vec3.create();
    const normalized = vec3.create();

    for (let vert = 0; vert < vertexCount; vert += 1)
    {
        // NOTE: some meshes don't have index 0 - n in their indexbuffer, if this is the case, skip calculation of this vertex
        if (!tempVertices[vert]) continue;

        vec3.set(normal, this.vertexNormals[vert * 3], this.vertexNormals[vert * 3 + 1], this.vertexNormals[vert * 3 + 2]);
        vec3.set(tempVert, tempVertices[vert][0], tempVertices[vert][1], tempVertices[vert][2]);

        // Gram-Schmidt orthagonalize
        const _dp = vec3.dot(normal, tempVert);
        vec3.scale(temp1, normal, _dp);
        vec3.subtract(temp2, tempVert, temp1);

        vec3.normalize(normalized, temp2);
        vec3.cross(crossPd, normal, tempVert);

        // const intermDot = vec3.dot(crossPd, tempVertices[vert + vertexCount]);
        const w = 1.0;// intermDot < 0.0 ? -1.0 : 1.0;

        vec3.scale(tan, normalized, 1 / w);
        vec3.cross(bitan, normal, tan);

        this.tangents[vert * 3 + 0] = tan[0];
        this.tangents[vert * 3 + 1] = tan[1];
        this.tangents[vert * 3 + 2] = tan[2];
        this.biTangents[vert * 3 + 0] = bitan[0];
        this.biTangents[vert * 3 + 1] = bitan[1];
        this.biTangents[vert * 3 + 2] = bitan[2];
    }
};

Geometry.prototype.isIndexed = function ()
{
    if (this._vertices.length == 0) return true;
    return this.verticesIndices.length != 0;
};

/**
 * @function unIndex
 * @memberof Geometry
 * @instance
 * @description remove all vertex indizes, vertices array will contain 3*XYZ for every triangle
 * @param {boolean} reIndex
 * @param {boolean} dontCalcNormals
 */
Geometry.prototype.unIndex = function (reIndex, dontCalcNormals)
{
    const newVerts = [];
    const newIndizes = [];
    let count = 0;

    for (let j in this._attributes)
    {
        const attr = this._attributes[j];
        let na = [];

        for (let i = 0; i < this.verticesIndices.length; i += 3)
        {
            for (let s = 0; s < 3; s++)
            {
                if (attr.itemSize == 3)
                    na.push(
                        attr.data[this.verticesIndices[i + s] * 3 + 0],
                        attr.data[this.verticesIndices[i + s] * 3 + 1],
                        attr.data[this.verticesIndices[i + s] * 3 + 2]);
                else if (attr.itemSize == 4)
                    na.push(
                        attr.data[this.verticesIndices[i + s] * 4 + 0],
                        attr.data[this.verticesIndices[i + s] * 4 + 1],
                        attr.data[this.verticesIndices[i + s] * 4 + 2],
                        attr.data[this.verticesIndices[i + s] * 4 + 3]);
                else if (attr.itemSize == 2)
                    na.push(
                        attr.data[this.verticesIndices[i + s] * 2 + 0],
                        attr.data[this.verticesIndices[i + s] * 2 + 1]);
                else if (attr.itemSize == 1)
                    na.push(
                        attr.data[this.verticesIndices[i + s]]);
                else console.log("unknown attr", attr);
            }
        }
        this.setAttribute(attr.name, na, attr.itemSize);
    }

    for (let i = 0; i < this.verticesIndices.length; i += 3)
    {
        newVerts.push(
            this.vertices[this.verticesIndices[i + 0] * 3 + 0],
            this.vertices[this.verticesIndices[i + 0] * 3 + 1],
            this.vertices[this.verticesIndices[i + 0] * 3 + 2]);

        newIndizes.push(count);
        count++;

        newVerts.push(
            this.vertices[this.verticesIndices[i + 1] * 3 + 0],
            this.vertices[this.verticesIndices[i + 1] * 3 + 1],
            this.vertices[this.verticesIndices[i + 1] * 3 + 2]);

        newIndizes.push(count);
        count++;

        newVerts.push(
            this.vertices[this.verticesIndices[i + 2] * 3 + 0],
            this.vertices[this.verticesIndices[i + 2] * 3 + 1],
            this.vertices[this.verticesIndices[i + 2] * 3 + 2]);

        newIndizes.push(count);
        count++;
    }

    this.vertices = newVerts;

    this.verticesIndices = [];
    if (reIndex) this.verticesIndices = newIndizes;

    if (!dontCalcNormals) this.calculateNormals();
};

Geometry.prototype.calcBarycentric = function ()
{
    let barycentrics = [];
    barycentrics.length = this.vertices.length;
    for (let i = 0; i < this.vertices.length; i++) barycentrics[i] = 0;

    let count = 0;
    for (let i = 0; i < this.vertices.length; i += 3)
    {
        barycentrics[i + count] = 1;
        count++;
        if (count == 3) count = 0;
    }

    this.setAttribute("attrBarycentric", barycentrics, 3);
};

Geometry.prototype.getBounds = function ()
{
    return new BoundingBox(this);
};

Geometry.prototype.center = function (x, y, z)
{
    if (x === undefined)
    {
        x = true;
        y = true;
        z = true;
    }

    let i = 0;
    const bounds = this.getBounds();
    const offset = [bounds.minX + (bounds.maxX - bounds.minX) / 2, bounds.minY + (bounds.maxY - bounds.minY) / 2, bounds.minZ + (bounds.maxZ - bounds.minZ) / 2];

    for (i = 0; i < this.vertices.length; i += 3)
    {
        if (this.vertices[i + 0] == this.vertices[i + 0])
        {
            if (x) this.vertices[i + 0] -= offset[0];
            if (y) this.vertices[i + 1] -= offset[1];
            if (z) this.vertices[i + 2] -= offset[2];
        }
    }

    return offset;
};

Geometry.prototype.mapTexCoords2d = function ()
{
    const bounds = this.getBounds();
    const num = this.vertices.length / 3;

    this.texCoords = new Float32Array(num * 2);

    for (let i = 0; i < num; i++)
    {
        const vertX = this.vertices[i * 3 + 0];
        const vertY = this.vertices[i * 3 + 1];
        this.texCoords[i * 2 + 0] = vertX / (bounds.maxX - bounds.minX) + 0.5;
        this.texCoords[i * 2 + 1] = 1.0 - vertY / (bounds.maxY - bounds.minY) + 0.5;
    }
};


Geometry.prototype.getInfoOneLine = function ()
{
    let txt = "";
    if (this.faceVertCount == 3 && this.verticesIndices)txt += this.verticesIndices.length / 3;
    else txt += 0;

    txt += " tris ";

    if (this.vertices)txt += this.vertices.length / 3;
    else txt += 0;

    txt += " verts";

    return txt;
};

Geometry.prototype.getInfo = function ()
{
    const info = {};

    if (this.faceVertCount == 3 && this.verticesIndices)info.numFaces = this.verticesIndices.length / 3;
    else info.numFaces = 0;

    if (this.verticesIndices && this.verticesIndices.length)info.indices = this.verticesIndices.length;

    if (this.vertices)info.numVerts = this.vertices.length / 3;
    else info.numVerts = 0;

    if (this.vertexNormals) info.numNormals = this.vertexNormals.length / 3;
    else info.numNormals = 0;

    if (this.texCoords) info.numTexCoords = this.texCoords.length / 2;
    else info.numTexCoords = 0;

    if (this.tangents) info.numTangents = this.tangents.length / 3;
    else info.numTangents = 0;

    if (this.biTangents) info.numBiTangents = this.biTangents.length / 3;
    else info.numBiTangents = 0;

    if (this.biTangents) info.numBiTangents = this.biTangents.length / 3;
    else info.numBiTangents = 0;

    if (this.vertexColors) info.numVertexColors = this.vertexColors.length / 4;
    else info.numVertexColors = 0;

    if (this.getAttributes()) info.numAttribs = Object.keys(this.getAttributes()).length;
    else info.numAttribs = 0;

    info.isIndexed = this.isIndexed();

    return info;
};

// -----------------

// TODO : rewritwe circle op
Geometry.buildFromFaces = function (arr, name, optimize)
{
    const vertices = [];
    const verticesIndices = [];

    for (let i = 0; i < arr.length; i += 3)
    {
        const a = arr[i + 0];
        const b = arr[i + 1];
        const c = arr[i + 2];
        const face = [-1, -1, -1];

        if (optimize)
            for (let iv = 0; iv < vertices.length; iv += 3)
            {
                if (vertices[iv + 0] == a[0] && vertices[iv + 1] == a[1] && vertices[iv + 2] == a[2]) face[0] = iv / 3;
                if (vertices[iv + 0] == b[0] && vertices[iv + 1] == b[1] && vertices[iv + 2] == b[2]) face[1] = iv / 3;
                if (vertices[iv + 0] == c[0] && vertices[iv + 1] == c[1] && vertices[iv + 2] == c[2]) face[2] = iv / 3;
            }

        if (face[0] == -1)
        {
            vertices.push(a[0], a[1], a[2]);
            face[0] = (vertices.length - 1) / 3;
        }

        if (face[1] == -1)
        {
            vertices.push(b[0], b[1], b[2]);
            face[1] = (vertices.length - 1) / 3;
        }

        if (face[2] == -1)
        {
            vertices.push(c[0], c[1], c[2]);
            face[2] = (vertices.length - 1) / 3;
        }

        verticesIndices.push(parseInt(face[0], 10));
        verticesIndices.push(parseInt(face[1], 10));
        verticesIndices.push(parseInt(face[2], 10));
    }

    const geom = new Geometry(name);
    geom.name = name;
    geom.vertices = vertices;
    geom.verticesIndices = verticesIndices;

    return geom;
};




;// CONCATENATED MODULE: ./src/core/cgl/cgl_mesh.js




const MESH = {};
MESH.lastMesh = null;

/**
 * webgl renderable 3d object
 * @class
 * @namespace external:CGL
 * @hideconstructor
 * @param {Context} _cgl cgl
 * @param {Geometry} __geom geometry
 * @param {Number} _options glPrimitive
 * @example
 * const cgl=this._cgl
 * const mesh=new CGL.Mesh(cgl, geometry);
 *
 * function render()
 * {
 *   mesh.render(cgl.getShader());
 * }
 */
const Mesh = function (_cgl, __geom, _options)
{
    this._cgl = _cgl;

    let options = _options || {};
    if (CABLES.UTILS.isNumeric(options))options = { "glPrimitive": _options }; // old constructor fallback...
    this._log = new Logger("cgl_mesh");
    this._bufVertexAttrib = null;
    this._bufVerticesIndizes = this._cgl.gl.createBuffer();
    this._indexType = this._cgl.gl.UNSIGNED_SHORT;
    this._attributes = [];
    this._attribLocs = {};
    this._geom = null;
    this._lastShader = null;
    this._numInstances = 0;
    this._glPrimitive = options.glPrimitive;

    this.opId = options.opId || "";
    this._preWireframeGeom = null;
    this.addVertexNumbers = false;
    this._name = "unknown";

    this.feedBackAttributes = [];
    this.setGeom(__geom);

    this._feedBacks = [];
    this._feedBacksChanged = false;
    this._transformFeedBackLoc = -1;
    this._lastAttrUpdate = 0;

    this.memFreed = false;

    this._cgl.profileData.addHeavyEvent("mesh constructed", this._name);

    this._queryExt = null;

    Object.defineProperty(this, "numInstances", {
        get()
        {
            return this._numInstances;
        },
        set(v)
        {
            this.setNumInstances(v);
        },
    });
};

Mesh.prototype.freeMem = function ()
{
    this.memFreed = true;

    for (let i = 0; i < this._attributes.length; i++)
    {
        this._attributes[i].floatArray = null;
    }
};

/**
 * @function updateVertices
 * @memberof Mesh
 * @instance
 * @description update vertices only from a geometry
 * @param {Geometry} geom
 */
Mesh.prototype.updateVertices = function (geom)
{
    this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_POSITION, geom.vertices, 3);
    this._numVerts = geom.vertices.length / 3;
};

Mesh.prototype.setAttributePointer = function (attrName, name, stride, offset)
{
    for (let i = 0; i < this._attributes.length; i++)
    {
        if (this._attributes[i].name == attrName)
        {
            if (!this._attributes[i].pointer) this._attributes[i].pointer = [];

            this._attributes[i].pointer.push(
                {
                    "loc": -1,
                    "name": name,
                    "stride": stride,
                    "offset": offset,
                    "instanced": attrName == constants_CONSTANTS.SHADER.SHADERVAR_INSTANCE_MMATRIX,
                }
            );
        }
    }
};

Mesh.prototype.getAttribute = function (name)
{
    for (let i = 0; i < this._attributes.length; i++) if (this._attributes[i].name == name) return this._attributes[i];
};

Mesh.prototype.setAttributeRange = function (attr, array, start, end)
{
    if (!attr) return;
    if (!start && !end) return;

    if (!attr.name)
    {
        this._log.stack("no attrname?!");
    }

    this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, attr.buffer);
    this._cgl.profileData.profileMeshAttributes += (end - start) || 0;

    this._cgl.profileData.profileSingleMeshAttribute[this._name] = this._cgl.profileData.profileSingleMeshAttribute[this._name] || 0;
    this._cgl.profileData.profileSingleMeshAttribute[this._name] += (end - start) || 0;

    if (attr.numItems < array.length / attr.itemSize)
    {
        this._resizeAttr(array, attr);
    }

    if (end > array.length)
    {
        if (CABLES.platform.isDevEnv())
            this._log.log(this._cgl.canvas.id + " " + attr.name + " buffersubdata out of bounds ?", array.length, end, start, attr);
        // end = array.length - 1;
        return;
    }

    if (this._cgl.glVersion == 1) this._cgl.gl.bufferSubData(this._cgl.gl.ARRAY_BUFFER, 0, array); // probably slow/ maybe create and array with only changed size ??
    else this._cgl.gl.bufferSubData(this._cgl.gl.ARRAY_BUFFER, start * 4, array, start, (end - start));
};

Mesh.prototype._resizeAttr = function (array, attr)
{
    if (attr.buffer)
        this._cgl.gl.deleteBuffer(attr.buffer);

    attr.buffer = this._cgl.gl.createBuffer();
    this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, attr.buffer);
    this._bufferArray(array, attr);
    attr.numItems = array.length / attr.itemSize;// numItems;
};


Mesh.prototype._bufferArray = function (array, attr)
{
    let floatArray = attr.floatArray || null;
    if (!array) return;


    if (this._cgl.debugOneFrame)
    {
        console.log("_bufferArray", array.length, attr.name); // eslint-disable-line
    }

    if (!(array instanceof Float32Array))
    {
        if (attr && floatArray && floatArray.length == array.length)
        {
            floatArray.set(array);
            // floatArray = floatArray;
        }
        else
        {
            floatArray = new Float32Array(array);

            if (this._cgl.debugOneFrame)
            {
                console.log("_bufferArray create new float32array", array.length, attr.name); // eslint-disable-line
            }

            if (array.length > 10000)
            {
                this._cgl.profileData.profileNonTypedAttrib++;
                this._cgl.profileData.profileNonTypedAttribNames = "(" + this._name + ":" + attr.name + ")";
            }
        }
    }
    else floatArray = array;

    attr.arrayLength = floatArray.length;
    attr.floatArray = null;// floatArray;

    this._cgl.gl.bufferData(this._cgl.gl.ARRAY_BUFFER, floatArray, this._cgl.gl.DYNAMIC_DRAW);
};

/**
 * @function setAttribute
 * @description update attribute
 * @memberof Mesh
 * @instance
 * @param {String} attribute name
 * @param {Array} data
 * @param {Number} itemSize
 * @param {Object} options
 */
Mesh.prototype.addAttribute = Mesh.prototype.updateAttribute = Mesh.prototype.setAttribute = function (name, array, itemSize, options)
{
    if (!array)
    {
        this._log.error("mesh addAttribute - no array given! " + name);
        throw new Error();
    }
    let cb = null;
    let instanced = false;
    let i = 0;
    const numItems = array.length / itemSize;

    this._cgl.profileData.profileMeshAttributes += numItems || 0;

    if (typeof options == "function")
    {
        cb = options;
    }

    if (typeof options == "object")
    {
        if (options.cb) cb = options.cb;
        if (options.instanced) instanced = options.instanced;
    }

    if (name == constants_CONSTANTS.SHADER.SHADERVAR_INSTANCE_MMATRIX) instanced = true;


    for (i = 0; i < this._attributes.length; i++)
    {
        const attr = this._attributes[i];
        if (attr.name == name)
        {
            if (attr.numItems === numItems)
            {
            }
            else
            {
                // this._log.log("wrong buffer size", this._geom.name, attr.name, attr.numItems, numItems);
                this._resizeAttr(array, attr);
            }

            this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, attr.buffer);
            this._bufferArray(array, attr);

            return attr;
        }
    }

    // create new buffer...

    const buffer = this._cgl.gl.createBuffer();

    this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, buffer);
    // this._cgl.gl.bufferData(this._cgl.gl.ARRAY_BUFFER, floatArray, this._cgl.gl.DYNAMIC_DRAW);

    let type = this._cgl.gl.FLOAT;
    if (options && options.type) type = options.type;
    const attr = {
        "buffer": buffer,
        "name": name,
        "cb": cb,
        "itemSize": itemSize,
        "numItems": numItems,
        "startItem": 0,
        "instanced": instanced,
        "type": type
    };

    this._bufferArray(array, attr);

    if (name == constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_POSITION) this._bufVertexAttrib = attr;
    this._attributes.push(attr);
    this._attribLocs = {};

    return attr;
};

Mesh.prototype.getAttributes = function ()
{
    return this._attributes;
};

/**
 * @function updateTexCoords
 * @description update texture coordinates only from a geometry
 * @memberof Mesh
 * @instance
 * @param {Geometry} geom
 */
Mesh.prototype.updateTexCoords = function (geom)
{
    if (geom.texCoords && geom.texCoords.length > 0)
    {
        this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_TEXCOORD, geom.texCoords, 2);
    }
    else
    {
        const tcBuff = new Float32Array(Math.round((geom.vertices.length / 3) * 2));
        this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_TEXCOORD, tcBuff, 2);
    }
};


/**
 * @function updateNormals
 * @description update normals only from a geometry
 * @memberof Mesh
 * @instance
 * @param {Geometry} geom
 */
Mesh.prototype.updateNormals = function (geom)
{
    if (geom.vertexNormals && geom.vertexNormals.length > 0)
    {
        this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_NORMAL, geom.vertexNormals, 3);
    }
    else
    {
        const tcBuff = new Float32Array(Math.round((geom.vertices.length)));
        this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_NORMAL, tcBuff, 3);
    }
};


Mesh.prototype._setVertexNumbers = function (arr)
{
    if (!this._verticesNumbers || this._verticesNumbers.length != this._numVerts || arr)
    {
        if (arr) this._verticesNumbers = arr;
        else
        {
            this._verticesNumbers = new Float32Array(this._numVerts);
            for (let i = 0; i < this._numVerts; i++) this._verticesNumbers[i] = i;
        }

        this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_NUMBER, this._verticesNumbers, 1, (attr, geom, shader) =>
        {
            if (!shader.uniformNumVertices) shader.uniformNumVertices = new Uniform(shader, "f", "numVertices", this._numVerts);
            shader.uniformNumVertices.setValue(this._numVerts);

            // console.log("this._numVerts", this._numVerts, attr, shader.uniformNumVertices);
        });
    }
};

/**
 * @function setVertexIndices
 * @description update vertex indices / faces
 * @memberof Mesh
 * @instance
 * @param {array} vertIndices
 */
Mesh.prototype.setVertexIndices = function (vertIndices)
{
    if (!this._bufVerticesIndizes)
    {
        this._log.warn("no bufVerticesIndizes: " + this._name);
        return;
    }
    if (vertIndices.length > 0)
    {
        if (vertIndices instanceof Float32Array) this._log.warn("vertIndices float32Array: " + this._name);

        for (let i = 0; i < vertIndices.length; i++)
        {
            if (vertIndices[i] >= this._numVerts)
            {
                this._log.warn("invalid index in " + this._name, i, vertIndices[i]);
                return;
            }
        }

        this._cgl.gl.bindBuffer(this._cgl.gl.ELEMENT_ARRAY_BUFFER, this._bufVerticesIndizes);

        // todo cache this ?
        // if(!this.vertIndicesTyped || this.vertIndicesTyped.length!=this._geom.verticesIndices.length)

        if (vertIndices.length > 65535)
        {
            this.vertIndicesTyped = new Uint32Array(vertIndices);
            this._indexType = this._cgl.gl.UNSIGNED_INT;
        }
        else
        if (vertIndices instanceof Uint32Array)
        {
            this.vertIndicesTyped = vertIndices;
            this._indexType = this._cgl.gl.UNSIGNED_INT;
        }
        else
        if (!(vertIndices instanceof Uint16Array))
        {
            this.vertIndicesTyped = new Uint16Array(vertIndices);
            this._indexType = this._cgl.gl.UNSIGNED_SHORT;
        }
        else this.vertIndicesTyped = vertIndices;

        this._cgl.gl.bufferData(this._cgl.gl.ELEMENT_ARRAY_BUFFER, this.vertIndicesTyped, this._cgl.gl.DYNAMIC_DRAW);
        this._bufVerticesIndizes.itemSize = 1;
        this._bufVerticesIndizes.numItems = vertIndices.length;
    }
    else this._bufVerticesIndizes.numItems = 0;
};

/**
 * @function setGeom
 * @memberof Mesh
 * @instance
 * @description set geometry for mesh
 * @param {Geometry} geom
 * @param {boolean} removeRef
 */
Mesh.prototype.setGeom = function (geom, removeRef)
{
    this._geom = geom;
    if (geom.glPrimitive != null) this._glPrimitive = geom.glPrimitive;
    if (this._geom && this._geom.name) this._name = "mesh " + this._geom.name;

    MESH.lastMesh = null;
    this._cgl.profileData.profileMeshSetGeom++;

    this._disposeAttributes();

    this.updateVertices(this._geom);
    this.setVertexIndices(this._geom.verticesIndices);

    if (this.addVertexNumbers) this._setVertexNumbers();

    const geomAttribs = this._geom.getAttributes();

    const attribAssoc = {
        "texCoords": constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_TEXCOORD,
        "vertexNormals": constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_NORMAL,
        "vertexColors": constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_COLOR,
        "tangents": "attrTangent",
        "biTangents": "attrBiTangent",
    };

    for (const index in geomAttribs)
        if (geomAttribs[index].data && geomAttribs[index].data.length)
            this.setAttribute(attribAssoc[index] || index, geomAttribs[index].data, geomAttribs[index].itemSize);


    if (removeRef)
    {
        this._geom = null;
    }
};

Mesh.prototype._preBind = function (shader)
{
    for (let i = 0; i < this._attributes.length; i++)
        if (this._attributes[i].cb)
            this._attributes[i].cb(this._attributes[i], this._geom, shader);
};

Mesh.prototype._checkAttrLengths = function ()
{
    if (this.memFreed) return;
    // check length
    for (let i = 0; i < this._attributes.length; i++)
    {
        if (this._attributes[i].arrayLength / this._attributes[i].itemSize < this._attributes[0].arrayLength / this._attributes[0].itemSize)
        {
            let name = "unknown";
            if (this._geom)name = this._geom.name;
            // this._log.warn(
            //     name + ": " + this._attributes[i].name +
            //     " wrong attr length. is:", this._attributes[i].arrayLength / this._attributes[i].itemSize,
            //     " should be:", this._attributes[0].arrayLength / this._attributes[0].itemSize,
            // );
        }
    }
};

Mesh.prototype._bind = function (shader)
{
    if (!shader.isValid()) return;

    let attrLocs = [];
    if (this._attribLocs[shader.id]) attrLocs = this._attribLocs[shader.id];
    else this._attribLocs[shader.id] = attrLocs;

    this._lastShader = shader;
    if (shader.lastCompile > this._lastAttrUpdate || attrLocs.length != this._attributes.length)
    {
        this._lastAttrUpdate = shader.lastCompile;
        for (let i = 0; i < this._attributes.length; i++) attrLocs[i] = -1;
    }

    for (let i = 0; i < this._attributes.length; i++)
    {
        const attribute = this._attributes[i];
        if (attrLocs[i] == -1)
        {
            if (attribute._attrLocationLastShaderTime != shader.lastCompile)
            {
                attribute._attrLocationLastShaderTime = shader.lastCompile;
                attrLocs[i] = this._cgl.glGetAttribLocation(shader.getProgram(), attribute.name);
                // this._log.log('attribloc',attribute.name,attrLocs[i]);
                this._cgl.profileData.profileAttrLoc++;
            }
        }

        if (attrLocs[i] != -1)
        {
            this._cgl.gl.enableVertexAttribArray(attrLocs[i]);
            this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER, attribute.buffer);

            if (attribute.instanced)
            {
                // todo: easier way to fill mat4 attribs...
                if (attribute.itemSize <= 4)
                {
                    if (!attribute.itemSize || attribute.itemSize == 0) this._log.warn("instanced attrib itemsize error", this._geom.name, attribute);

                    this._cgl.gl.vertexAttribPointer(attrLocs[i], attribute.itemSize, attribute.type, false, attribute.itemSize * 4, 0);
                    this._cgl.gl.vertexAttribDivisor(attrLocs[i], 1);
                }
                else if (attribute.itemSize == 16)
                {
                    const stride = 16 * 4;

                    this._cgl.gl.vertexAttribPointer(attrLocs[i], 4, attribute.type, false, stride, 0);
                    this._cgl.gl.enableVertexAttribArray(attrLocs[i] + 1);
                    this._cgl.gl.vertexAttribPointer(attrLocs[i] + 1, 4, attribute.type, false, stride, 4 * 4 * 1);
                    this._cgl.gl.enableVertexAttribArray(attrLocs[i] + 2);
                    this._cgl.gl.vertexAttribPointer(attrLocs[i] + 2, 4, attribute.type, false, stride, 4 * 4 * 2);
                    this._cgl.gl.enableVertexAttribArray(attrLocs[i] + 3);
                    this._cgl.gl.vertexAttribPointer(attrLocs[i] + 3, 4, attribute.type, false, stride, 4 * 4 * 3);

                    this._cgl.gl.vertexAttribDivisor(attrLocs[i], 1);
                    this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 1, 1);
                    this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 2, 1);
                    this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 3, 1);
                }
                else
                {
                    this._log.warn("unknown instance attrib size", attribute.name);
                }
            }
            else
            {
                if (!attribute.itemSize || attribute.itemSize == 0) this._log.warn("attrib itemsize error", this._name, attribute);
                this._cgl.gl.vertexAttribPointer(attrLocs[i], attribute.itemSize, attribute.type, false, attribute.itemSize * 4, 0);

                if (attribute.pointer)
                {
                    for (let ip = 0; ip < attribute.pointer.length; ip++)
                    {
                        const pointer = attribute.pointer[ip];

                        if (pointer.loc == -1)
                            pointer.loc = this._cgl.glGetAttribLocation(shader.getProgram(), pointer.name);

                        this._cgl.profileData.profileAttrLoc++;

                        this._cgl.gl.enableVertexAttribArray(pointer.loc);
                        this._cgl.gl.vertexAttribPointer(pointer.loc, attribute.itemSize, attribute.type, false, pointer.stride, pointer.offset);
                    }
                }
                if (this.bindFeedback) this.bindFeedback(attribute);
            }
        }
    }

    if (this._bufVerticesIndizes && this._bufVerticesIndizes.numItems !== 0) this._cgl.gl.bindBuffer(this._cgl.gl.ELEMENT_ARRAY_BUFFER, this._bufVerticesIndizes);
};

Mesh.prototype.unBind = function ()
{
    const shader = this._lastShader;
    this._lastShader = null;
    if (!shader) return;

    let attrLocs = [];
    if (this._attribLocs[shader.id]) attrLocs = this._attribLocs[shader.id];
    else this._attribLocs[shader.id] = attrLocs;

    MESH.lastMesh = null;

    for (let i = 0; i < this._attributes.length; i++)
    {
        if (this._attributes[i].instanced)
        {
            // todo: easier way to fill mat4 attribs...
            if (this._attributes[i].itemSize <= 4)
            {
                if (attrLocs[i] != -1) this._cgl.gl.vertexAttribDivisor(attrLocs[i], 0);
                if (attrLocs[i] >= 0) this._cgl.gl.disableVertexAttribArray(attrLocs[i]);
            }
            else
            {
                this._cgl.gl.vertexAttribDivisor(attrLocs[i], 0);
                this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 1, 0);
                this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 2, 0);
                this._cgl.gl.vertexAttribDivisor(attrLocs[i] + 3, 0);
                this._cgl.gl.disableVertexAttribArray(attrLocs[i] + 1);
                this._cgl.gl.disableVertexAttribArray(attrLocs[i] + 2);
                this._cgl.gl.disableVertexAttribArray(attrLocs[i] + 3);
            }
        }

        if (attrLocs[i] != -1) this._cgl.gl.disableVertexAttribArray(attrLocs[i]);
    }
};

Mesh.prototype.meshChanged = function ()
{
    return this._cgl.lastMesh && this._cgl.lastMesh != this;
};

Mesh.prototype.printDebug = function (shader)
{
    console.log("--attributes");
    for (let i = 0; i < this._attributes.length; i++)
    {
        console.log("attribute " + i + " " + this._attributes[i].name);
    }
};

Mesh.prototype.setNumVertices = function (num)
{
    this._bufVertexAttrib.numItems = num;
};

Mesh.prototype.getNumVertices = function ()
{
    return this._bufVertexAttrib.numItems;
};


/**
 * @function render
 * @memberof Mesh
 * @instance
 * @description draw mesh to screen
 * @param {Shader} shader
 */
Mesh.prototype.render = function (shader)
{
    // TODO: enable/disablevertex only if the mesh has changed... think drawing 10000x the same mesh

    if (!shader || !shader.isValid() || this._cgl.aborted) return;

    this._checkAttrLengths();

    if (this._geom)
    {
        if (this._preWireframeGeom && !shader.wireframe && !this._geom.isIndexed())
        {
            this.setGeom(this._preWireframeGeom);
            this._preWireframeGeom = null;
            // console.log("remove prewireframe geom");
        }

        if (shader.wireframe)
        {
            let changed = false;

            if (this._geom.isIndexed())
            {
                if (!this._preWireframeGeom)
                {
                    this._preWireframeGeom = this._geom;
                    this._geom = this._geom.copy();
                }

                this._geom.unIndex();
                changed = true;
            }

            if (!this._geom.getAttribute("attrBarycentric"))
            {
                if (!this._preWireframeGeom)
                {
                    this._preWireframeGeom = this._geom;
                    this._geom = this._geom.copy();
                }
                changed = true;

                this._geom.calcBarycentric();
            }
            if (changed) this.setGeom(this._geom);
        }
        // if (shader.wireframe)
        // console.log(shader.wireframe, this._geom.isIndexed());
    }

    let needsBind = false;
    if (MESH.lastMesh != this)
    {
        if (MESH.lastMesh) MESH.lastMesh.unBind();
        needsBind = true;
    }


    // var needsBind=false;
    // {
    //     needsBind=true;
    // }
    if (needsBind) this._preBind(shader);

    if (!shader.bind()) return;

    // if(needsBind)
    this._bind(shader);
    if (this.addVertexNumbers) this._setVertexNumbers();

    MESH.lastMesh = this;

    let prim = this._cgl.gl.TRIANGLES;
    if (this._glPrimitive !== undefined) prim = this._glPrimitive;
    if (shader.glPrimitive !== null) prim = shader.glPrimitive;

    let elementDiv = 1;
    let doQuery = this._cgl.profileData.doProfileGlQuery;
    let queryStarted = false;
    if (doQuery)
    {
        let id = this._name + " - " + shader.getName() + " #" + shader.id;
        if (this._numInstances) id += " instanced " + this._numInstances + "x";

        let queryProfilerData = this._cgl.profileData.glQueryData[id];

        if (!queryProfilerData) queryProfilerData = { "id": id, "num": 0 };

        if (shader.opId)queryProfilerData.shaderOp = shader.opId;
        if (this.opId)queryProfilerData.meshOp = this.opId;

        this._cgl.profileData.glQueryData[id] = queryProfilerData;

        if (!this._queryExt && this._queryExt !== false) this._queryExt = this._cgl.enableExtension("EXT_disjoint_timer_query_webgl2") || false;
        if (this._queryExt)
        {
            if (queryProfilerData._drawQuery)
            {
                const available = this._cgl.gl.getQueryParameter(queryProfilerData._drawQuery, this._cgl.gl.QUERY_RESULT_AVAILABLE);
                if (available)
                {
                    const elapsedNanos = this._cgl.gl.getQueryParameter(queryProfilerData._drawQuery, this._cgl.gl.QUERY_RESULT);
                    const currentTimeGPU = elapsedNanos / 1000000;

                    queryProfilerData._times = queryProfilerData._times || 0;
                    queryProfilerData._times += currentTimeGPU;
                    queryProfilerData._numcount++;
                    queryProfilerData.when = performance.now();
                    queryProfilerData._drawQuery = null;
                    queryProfilerData.queryStarted = false;
                }
            }

            if (!queryProfilerData.queryStarted)
            {
                queryProfilerData._drawQuery = this._cgl.gl.createQuery();
                this._cgl.gl.beginQuery(this._queryExt.TIME_ELAPSED_EXT, queryProfilerData._drawQuery);
                queryStarted = queryProfilerData.queryStarted = true;
            }
        }
    }


    if (this.hasFeedbacks && this.hasFeedbacks()) this.drawFeedbacks(shader, prim);
    else if (!this._bufVerticesIndizes || this._bufVerticesIndizes.numItems === 0)
    {
        // for (let i = 0; i < this._attributes.length; i++)
        // {
        //     if (this._attributes[i].arrayLength / this._attributes[i].itemSize != this._bufVertexAttrib.floatArray.length / 3)
        //     {
        //         this._log.warn("attrib buffer length wrong! ", this._attributes[i].name, this._attributes[i].arrayLength / this._attributes[i].itemSize, this._bufVertexAttrib.floatArray.length / 3, this._attributes[i].itemSize);
        //         // this._log.log(this);
        //         // debugger;
        //         return;
        //     }
        // }


        if (prim == this._cgl.gl.TRIANGLES)elementDiv = 3;
        if (this._numInstances === 0) this._cgl.gl.drawArrays(prim, this._bufVertexAttrib.startItem, this._bufVertexAttrib.numItems - this._bufVertexAttrib.startItem);
        else this._cgl.gl.drawArraysInstanced(prim, this._bufVertexAttrib.startItem, this._bufVertexAttrib.numItems, this._numInstances);
    }
    else
    {
        if (prim == this._cgl.gl.TRIANGLES)elementDiv = 3;
        if (this._numInstances === 0)
        {
            // console.log("la", this._bufVerticesIndizes.numItems);

            this._cgl.gl.drawElements(prim, this._bufVerticesIndizes.numItems, this._indexType, 0);
        }
        else
        {
            this._cgl.gl.drawElementsInstanced(prim, this._bufVerticesIndizes.numItems, this._indexType, 0, this._numInstances);
        }
    }

    if (this._cgl.debugOneFrame && this._cgl.gl.getError() != this._cgl.gl.NO_ERROR)
    {
        this._log.error("mesh draw gl error");
        this._log.error("mesh", this);
        this._log.error("shader", shader);

        const attribNames = [];
        for (let i = 0; i < this._cgl.gl.getProgramParameter(shader.getProgram(), this._cgl.gl.ACTIVE_ATTRIBUTES); i++)
        {
            const name = this._cgl.gl.getActiveAttrib(shader.getProgram(), i).name;
            this._log.error("attrib ", name);
        }
    }

    this._cgl.profileData.profileMeshNumElements += (this._bufVertexAttrib.numItems / elementDiv) * (this._numInstances || 1);
    this._cgl.profileData.profileMeshDraw++;

    if (doQuery && queryStarted)
    {
        this._cgl.gl.endQuery(this._queryExt.TIME_ELAPSED_EXT);
    }

    this._cgl.printError("mesh render " + this._name);

    this.unBind();
};

Mesh.prototype.setNumInstances = function (n)
{
    n = Math.max(0, n);
    if (this._numInstances != n)
    {
        this._numInstances = n;
        const indexArr = new Float32Array(n);
        for (let i = 0; i < n; i++) indexArr[i] = i;
        this.setAttribute(constants_CONSTANTS.SHADER.SHADERVAR_INSTANCE_INDEX, indexArr, 1, { "instanced": true });
    }
};

Mesh.prototype._disposeAttributes = function ()
{
    if (!this._attributes) return;

    for (let i = 0; i < this._attributes.length; i++)
    {
        if (this._attributes[i].buffer)
        {
            this._cgl.gl.deleteBuffer(this._attributes[i].buffer);
            this._attributes[i].buffer = null;
        }
    }
    this._attributes.length = 0;
};

Mesh.prototype.dispose = function ()
{
    if (this._bufVertexAttrib && this._bufVertexAttrib.buffer) this._cgl.gl.deleteBuffer(this._bufVertexAttrib.buffer);
    if (this._bufVerticesIndizes) this._cgl.gl.deleteBuffer(this._bufVerticesIndizes);
    this._bufVerticesIndizes = null;

    this._disposeAttributes();
};





;// CONCATENATED MODULE: ./src/core/cgl/cgl_simplerect.js




const MESHES = {};

MESHES.getSimpleRect = function (cgl, name, size = 1.0)
{
    const geom = new Geometry(name);



    geom.vertices = [1.0 * size, 1.0 * size, 0.0, -1.0 * size, 1.0 * size, 0.0, 1.0 * size, -1.0 * size, 0.0, -1.0 * size, -1.0 * size, 0.0];
    geom.texCoords = [1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0];
    geom.verticesIndices = [0, 1, 2, 2, 1, 3];
    geom.vertexNormals = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];

    return cgl.createMesh(geom);
    // return new Mesh(cgl, geom);
};


MESHES.getSimpleCube = function (cgl, name)
{
    const geom = new Geometry(name);
    geom.vertices = [-1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, 1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1, 1, -1];
    geom.setTexCoords([0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0,]);
    geom.verticesIndices = [0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23];
    geom.vertexNormals = new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0]);
    geom.tangents = new Float32Array([0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1]);
    geom.biTangents = new Float32Array([-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1]);

    return new Mesh(cgl, geom);
};




;// CONCATENATED MODULE: ./src/core/cgl/cgl_textureeffect.js




const TextureEffect = function (cgl, options)
{
    this._cgl = cgl;
    this._log = new Logger("cgl_TextureEffect");

    if (!cgl.TextureEffectMesh) this.createMesh();

    this._textureSource = null;
    this._options = options;
    this.name = options.name || "unknown";

    // TODO: do we still need the options ?
    // var opts=options ||
    //     {
    //         isFloatingPointTexture:false,
    //         filter:CGL.Texture.FILTER_LINEAR
    //     };
    // if(options && options.fp)opts.isFloatingPointTexture=true;

    this.imgCompVer = 0;
    this.aspectRatio = 1;
    this._textureTarget = null; // new CGL.Texture(this._cgl,opts);
    this._frameBuf = this._cgl.gl.createFramebuffer();
    this._frameBuf2 = this._cgl.gl.createFramebuffer();
    this._renderbuffer = this._cgl.gl.createRenderbuffer();
    this._renderbuffer2 = this._cgl.gl.createRenderbuffer();
    this.switched = false;
    this.depth = false;
};

TextureEffect.prototype.dispose = function ()
{
    if (this._renderbuffer) this._cgl.gl.deleteRenderbuffer(this._renderbuffer);
    if (this._frameBuf) this._cgl.gl.deleteFramebuffer(this._frameBuf);
    if (this._renderbuffer2) this._cgl.gl.deleteRenderbuffer(this._renderbuffer2);
    if (this._frameBuf2) this._cgl.gl.deleteFramebuffer(this._frameBuf2);
};

TextureEffect.prototype.getWidth = function ()
{
    return this._textureSource.width;
};

TextureEffect.prototype.getHeight = function ()
{
    return this._textureSource.height;
};

TextureEffect.prototype.setSourceTexture = function (tex)
{
    if (tex === null)
    {
        this._textureSource = new Texture(this._cgl);
        this._textureSource.setSize(16, 16);
    }
    else
    {
        this._textureSource = tex;
    }

    if (!this._textureSource.compareSettings(this._textureTarget))
    {
        if (this._textureTarget) this._textureTarget.delete();

        this._textureTarget = this._textureSource.clone();

        this._cgl.profileData.profileEffectBuffercreate++;

        this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuf);

        this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, this._renderbuffer);

        // if(tex.textureType==CGL.Texture.TYPE_FLOAT) this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,this._cgl.gl.RGBA32F, this._textureSource.width,this._textureSource.height);
        // else this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,this._cgl.gl.RGBA8, this._textureSource.width,this._textureSource.height);

        if (this.depth) this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, this._cgl.gl.DEPTH_COMPONENT16, this._textureSource.width, this._textureSource.height);
        this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._textureTarget.tex, 0);
        if (this.depth) this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._renderbuffer);

        // this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._textureTarget.tex, 0);

        this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, null);
        this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, null);
        this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null);

        this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuf2);

        this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, this._renderbuffer2);

        // if(tex.textureType==CGL.Texture.TYPE_FLOAT) this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,this._cgl.gl.RGBA32F, this._textureSource.width,this._textureSource.height);
        // else this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,this._cgl.gl.RGBA8, this._textureSource.width,this._textureSource.height);

        if (this.depth) this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, this._cgl.gl.DEPTH_COMPONENT16, this._textureSource.width, this._textureSource.height);
        this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._textureSource.tex, 0);

        if (this.depth) this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._renderbuffer2);

        // this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._textureSource.tex, 0);

        this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, null);
        this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, null);
        this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null);
    }

    this.aspectRatio = this._textureSource.width / this._textureSource.height;
};
TextureEffect.prototype.continueEffect = function ()
{
    this._cgl.pushDepthTest(false);
    this._cgl.pushModelMatrix();
    this._cgl.pushPMatrix();
    // todo why two pushs?



    this._cgl.pushViewPort(0, 0, this.getCurrentTargetTexture().width, this.getCurrentTargetTexture().height);



    mat4.perspective(this._cgl.pMatrix, 45, this.getCurrentTargetTexture().width / this.getCurrentTargetTexture().height, 0.1, 1100.0); // todo: why?

    this._cgl.pushPMatrix();
    mat4.identity(this._cgl.pMatrix);

    this._cgl.pushViewMatrix();
    mat4.identity(this._cgl.vMatrix);

    this._cgl.pushModelMatrix();
    mat4.identity(this._cgl.mMatrix);
};


TextureEffect.prototype.startEffect = function (bgTex)
{
    if (!this._textureTarget)
    {
        this._log.warn("effect has no target");
        return;
    }

    this.switched = false;

    this.continueEffect();

    if (bgTex)
    {
        this._bgTex = bgTex;
    }
    this._countEffects = 0;
};

TextureEffect.prototype.endEffect = function ()
{
    this._cgl.popDepthTest();
    this._cgl.popModelMatrix();

    this._cgl.popPMatrix();
    this._cgl.popModelMatrix();
    this._cgl.popViewMatrix();

    this._cgl.popPMatrix();
    this._cgl.popViewPort();
};

TextureEffect.prototype.bind = function ()
{
    if (this._textureSource === null)
    {
        this._log.warn("no base texture set!");
        return;
    }

    if (!this.switched)
    {
        this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuf);
        this._cgl.pushGlFrameBuffer(this._frameBuf);
    }
    else
    {
        this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuf2);
        this._cgl.pushGlFrameBuffer(this._frameBuf2);
    }
};

TextureEffect.prototype.finish = function ()
{
    if (this._textureSource === null)
    {
        this._log.warn("no base texture set!");
        return;
    }

    this._cgl.TextureEffectMesh.render(this._cgl.getShader());

    this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.popGlFrameBuffer());

    this._cgl.profileData.profileTextureEffect++;

    if (this._textureTarget.filter == Texture.FILTER_MIPMAP)
    {
        if (!this.switched)
        {
            this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, this._textureTarget.tex);
            this._textureTarget.updateMipMap();
        }
        else
        {
            this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, this._textureSource.tex);
            this._textureSource.updateMipMap();
        }

        this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, null);
    }

    this.switched = !this.switched;
    this._countEffects++;
};

TextureEffect.prototype.getCurrentTargetTexture = function ()
{
    if (this.switched) return this._textureSource;
    return this._textureTarget;
};

TextureEffect.prototype.getCurrentSourceTexture = function ()
{
    if (this._countEffects == 0 && this._bgTex) return this._bgTex;

    if (this.switched) return this._textureTarget;
    return this._textureSource;
};

TextureEffect.prototype.delete = function ()
{
    if (this._textureTarget) this._textureTarget.delete();
    if (this._textureSource) this._textureSource.delete();
    this._cgl.gl.deleteRenderbuffer(this._renderbuffer);
    this._cgl.gl.deleteFramebuffer(this._frameBuf);
};

TextureEffect.prototype.createMesh = function ()
{
    this._cgl.TextureEffectMesh = MESHES.getSimpleRect(this._cgl, "texEffectRect");
};

// ---------------------------------------------------------------------------------

TextureEffect.checkOpNotInTextureEffect = function (op)
{
    if (!op.patch.cgl) return true;
    if (op.uiAttribs.error && !op.patch.cgl.currentTextureEffect)
    {
        op.setUiError("textureeffect", null);
        return true;
    }
    if (!op.patch.cgl.currentTextureEffect) return true;

    if (op.patch.cgl.currentTextureEffect && !op.uiAttribs.error)
    {
        op.setUiError("textureeffect", "This op can not be a child of a ImageCompose/texture effect! imagecompose should only have textureeffect childs.", 0);
        return false;
    }

    if (op.patch.cgl.currentTextureEffect) return false;
    return true;
};

TextureEffect.checkOpInEffect = function (op, minver)
{
    minver = minver || 0;

    if (op.patch.cgl.currentTextureEffect)
    {
        if (op.uiAttribs.uierrors && op.patch.cgl.currentTextureEffect.imgCompVer >= minver)
        {
            op.setUiError("texeffect", null);
            return true;
        }

        if (minver && op.patch.cgl.currentTextureEffect.imgCompVer < minver)
        {
            op.setUiError("texeffect", "This op must be a child of an ImageCompose op with version >=" + minver + " <span class=\"button-small\" onclick=\"gui.patchView.downGradeOp('" + op.id + "','" + op.name + "')\">Downgrade</span> to previous version", 1);
        }
    }

    if (op.patch.cgl.currentTextureEffect) return true;

    if (!op.patch.cgl.currentTextureEffect && (!op.uiAttribs.uierrors || op.uiAttribs.uierrors.length == 0))
    {
        op.setUiError("texeffect", "This op must be a child of an ImageCompose op! More infos <a href=\"https://cables.gl/docs/image_composition/image_composition.html\" target=\"_blank\">here</a>. ", 1);
        return false;
    }

    if (!op.patch.cgl.currentTextureEffect) return false;
    return true;
};

TextureEffect.getBlendCode = function (ver)
{
    let src = "".endl()
        + "vec3 _blend(vec3 base,vec3 blend)".endl()
        + "{".endl()
        + "   vec3 colNew=blend;".endl()
        + "   #ifdef BM_MULTIPLY".endl()
        + "       colNew=base*blend;".endl()
        + "   #endif".endl()
        + "   #ifdef BM_MULTIPLY_INV".endl()
        + "       colNew=base* vec3(1.0)-blend;".endl()
        + "   #endif".endl()
        + "   #ifdef BM_AVERAGE".endl()
        + "       colNew=((base + blend) / 2.0);".endl()
        + "   #endif".endl()
        + "   #ifdef BM_ADD".endl()
        + "       colNew=min(base + blend, vec3(1.0));".endl()
        + "   #endif".endl()
        + "   #ifdef BM_SUBTRACT_ONE".endl()
        + "       colNew=max(base + blend - vec3(1.0), vec3(0.0));".endl()
        + "   #endif".endl()

        + "   #ifdef BM_SUBTRACT".endl()
        + "       colNew=base - blend;".endl()
        + "   #endif".endl()

        + "   #ifdef BM_DIFFERENCE".endl()
        + "       colNew=abs(base - blend);".endl()
        + "   #endif".endl()
        + "   #ifdef BM_NEGATION".endl()
        + "       colNew=(vec3(1.0) - abs(vec3(1.0) - base - blend));".endl()
        + "   #endif".endl()
        + "   #ifdef BM_EXCLUSION".endl()
        + "       colNew=(base + blend - 2.0 * base * blend);".endl()
        + "   #endif".endl()
        + "   #ifdef BM_LIGHTEN".endl()
        + "       colNew=max(blend, base);".endl()
        + "   #endif".endl()
        + "   #ifdef BM_DARKEN".endl()
        + "       colNew=min(blend, base);".endl()
        + "   #endif".endl()
        + "   #ifdef BM_OVERLAY".endl()
        + "      #define BlendOverlayf(base, blend)  (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)))"
            // .endl()+'       #define BlendOverlay(base, blend)       Blend(base, blend, BlendOverlayf)'
            //    .endl()+'      colNew=Blend(base, blend, BlendOverlayf);'
            .endl()
        + "      colNew=vec3(BlendOverlayf(base.r, blend.r),BlendOverlayf(base.g, blend.g),BlendOverlayf(base.b, blend.b));".endl()
        + "   #endif".endl()
        + "   #ifdef BM_SCREEN".endl()
        + "      #define BlendScreenf(base, blend)       (1.0 - ((1.0 - base) * (1.0 - blend)))"
            // .endl()+'       #define BlendScreen(base, blend)        Blend(base, blend, BlendScreenf)'
            // .endl()+'      colNew=Blend(base, blend, BlendScreenf);'
            .endl()
        + "      colNew=vec3(BlendScreenf(base.r, blend.r),BlendScreenf(base.g, blend.g),BlendScreenf(base.b, blend.b));".endl()
        + "   #endif".endl()
        + "   #ifdef BM_SOFTLIGHT".endl()
        + "      #define BlendSoftLightf(base, blend)    ((blend < 0.5) ? (2.0 * base * blend + base * base * (1.0 - 2.0 * blend)) : (sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend)))"
            // .endl()+'       #define BlendSoftLight(base, blend)     Blend(base, blend, BlendSoftLightf)'
            //    .endl()+'      colNew=Blend(base, blend, BlendSoftLightf);'
            .endl()
        + "      colNew=vec3(BlendSoftLightf(base.r, blend.r),BlendSoftLightf(base.g, blend.g),BlendSoftLightf(base.b, blend.b));".endl()
        + "   #endif".endl()
        + "   #ifdef BM_HARDLIGHT".endl()
        + "      #define BlendOverlayf(base, blend)  (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)))"
            // .endl()+'       #define BlendOverlay(base, blend)       Blend(base, blend, BlendOverlayf)'
            // .endl()+'      colNew=Blend(blend, base, BlendOverlayf);'
            .endl()
        + "      colNew=vec3(BlendOverlayf(base.r, blend.r),BlendOverlayf(base.g, blend.g),BlendOverlayf(base.b, blend.b));".endl()
        + "   #endif".endl()
        + "   #ifdef BM_COLORDODGE".endl()
        + "      #define BlendColorDodgef(base, blend)   ((blend == 1.0) ? blend : min(base / (1.0 - blend), 1.0))"
            // .endl()+'      colNew=Blend(base, blend, BlendColorDodgef);'
            .endl()
        + "      colNew=vec3(BlendColorDodgef(base.r, blend.r),BlendColorDodgef(base.g, blend.g),BlendColorDodgef(base.b, blend.b));".endl()
        + "   #endif".endl()
        + "   #ifdef BM_COLORBURN".endl()
        + "      #define BlendColorBurnf(base, blend)    ((blend == 0.0) ? blend : max((1.0 - ((1.0 - base) / blend)), 0.0))"
            // .endl()+'      colNew=Blend(base, blend, BlendColorBurnf);'
            .endl()
        + "      colNew=vec3(BlendColorBurnf(base.r, blend.r),BlendColorBurnf(base.g, blend.g),BlendColorBurnf(base.b, blend.b));".endl()
        + "   #endif".endl()










        + "   return colNew;".endl()
        + "}".endl();

    if (!ver)
        src += "vec4 cgl_blend(vec4 oldColor,vec4 newColor,float amount)".endl()
                + "{".endl()
                    + "vec4 col=vec4( _blend(oldColor.rgb,newColor.rgb) ,1.0);".endl()
                    + "col=vec4( mix( col.rgb, oldColor.rgb ,1.0-oldColor.a*amount),1.0);".endl()
                    + "return col;".endl()
                + "}".endl();

    if (ver >= 3)
        src += "vec4 cgl_blendPixel(vec4 base,vec4 col,float amount)".endl() +
                "{".endl() +

                "#ifdef BM_MATH_ADD".endl() +
                "   return vec4(base.rgb+col.rgb*amount,1.0);".endl() +
                "#endif".endl() +

                "#ifdef BM_MATH_SUB".endl() +
                "   return vec4(base.rgb-col.rgb*amount,1.0);".endl() +
                "#endif".endl() +

                "#ifdef BM_MATH_MUL".endl() +
                "   return vec4(base.rgb*col.rgb*amount,1.0);".endl() +
                "#endif".endl() +

                "#ifdef BM_MATH_DIV".endl() +
                "   return vec4(base.rgb/col.rgb*amount,1.0);".endl() +
                "#endif".endl() +


                    "#ifndef BM_MATH".endl() +
                        "vec3 colNew=_blend(base.rgb,col.rgb);".endl() +

                        "float newA=clamp(base.a+(col.a*amount),0.,1.);".endl() +

                        "#ifdef BM_ALPHAMASKED".endl() +
                            "newA=base.a;".endl() +
                        "#endif".endl() +

                        "return vec4(".endl() +
                            "mix(colNew,base.rgb,1.0-(amount*col.a)),".endl() +
                            "newA);".endl() +

                    "#endif".endl() +
    "}".endl();

    return src;
};

TextureEffect.onChangeBlendSelect = function (shader, blendName, maskAlpha = false)
{
    blendName = String(blendName);
    shader.toggleDefine("BM_NORMAL", blendName == "normal");
    shader.toggleDefine("BM_MULTIPLY", blendName == "multiply");
    shader.toggleDefine("BM_MULTIPLY_INV", blendName == "multiply invert");
    shader.toggleDefine("BM_AVERAGE", blendName == "average");
    shader.toggleDefine("BM_ADD", blendName == "add");
    shader.toggleDefine("BM_SUBTRACT_ONE", blendName == "subtract one");
    shader.toggleDefine("BM_SUBTRACT", blendName == "subtract");
    shader.toggleDefine("BM_DIFFERENCE", blendName == "difference");
    shader.toggleDefine("BM_NEGATION", blendName == "negation");
    shader.toggleDefine("BM_EXCLUSION", blendName == "exclusion");
    shader.toggleDefine("BM_LIGHTEN", blendName == "lighten");
    shader.toggleDefine("BM_DARKEN", blendName == "darken");
    shader.toggleDefine("BM_OVERLAY", blendName == "overlay");
    shader.toggleDefine("BM_SCREEN", blendName == "screen");
    shader.toggleDefine("BM_SOFTLIGHT", blendName == "softlight");
    shader.toggleDefine("BM_HARDLIGHT", blendName == "hardlight");
    shader.toggleDefine("BM_COLORDODGE", blendName == "color dodge");
    shader.toggleDefine("BM_COLORBURN", blendName == "color burn");

    shader.toggleDefine("BM_MATH_ADD", blendName == "Math Add");
    shader.toggleDefine("BM_MATH_SUB", blendName == "Math Subtract");
    shader.toggleDefine("BM_MATH_MUL", blendName == "Math Multiply");
    shader.toggleDefine("BM_MATH_DIV", blendName == "Math Divide");

    shader.toggleDefine("BM_MATH", blendName.indexOf("Math ") == 0);


    shader.toggleDefine("BM_ALPHAMASKED", maskAlpha);
};

TextureEffect.AddBlendSelect = function (op, name, defaultMode)
{
    const p = op.inValueSelect(name || "Blend Mode", [
        "normal", "lighten", "darken", "multiply", "multiply invert", "average", "add", "subtract", "difference", "negation", "exclusion", "overlay", "screen", "color dodge", "color burn", "softlight", "hardlight", "subtract one",
        "Math Add",
        "Math Subtract",
        "Math Multiply",
        "Math Divide",

    ], defaultMode || "normal");
    return p;
};

TextureEffect.AddBlendAlphaMask = function (op, name, defaultMode)
{
    const p = op.inSwitch(name || "Alpha Mask", ["Off", "On"], defaultMode || "Off");
    return p;
};

TextureEffect.setupBlending = function (op, shader, blendPort, amountPort, alphaMaskPort)
{
    const onChange = () =>
    {
        let maskAlpha = false;
        if (alphaMaskPort) maskAlpha = alphaMaskPort.get() == "On";
        TextureEffect.onChangeBlendSelect(shader, blendPort.get(), maskAlpha);

        let str = blendPort.get();
        if (str == "normal") str = null;
        else if (str == "multiply") str = "mul";
        else if (str == "multiply invert") str = "mulinv";
        else if (str == "lighten") str = "light";
        else if (str == "darken") str = "darken";
        else if (str == "average") str = "avg";
        else if (str == "subtract one") str = "sub one";
        else if (str == "subtract") str = "sub";
        else if (str == "difference") str = "diff";
        else if (str == "negation") str = "neg";
        else if (str == "exclusion") str = "exc";
        else if (str == "overlay") str = "ovl";
        else if (str == "color dodge") str = "dodge";
        else if (str == "color burn") str = "burn";
        else if (str == "softlight") str = "soft";
        else if (str == "hardlight") str = "hard";
        else if (str == "Math Add") str = "+";
        else if (str == "Math Subtract") str = "-";
        else if (str == "Math Multiply") str = "*";
        else if (str == "Math Divide") str = "/";

        op.setUiAttrib({ "extendTitle": str });
    };
    op.setPortGroup("Blending", [blendPort, amountPort, alphaMaskPort]);

    let maskAlpha = false;

    blendPort.onChange = onChange;
    if (alphaMaskPort)
    {
        alphaMaskPort.onChange = onChange;
        maskAlpha = alphaMaskPort.get() == "On";
    }

    TextureEffect.onChangeBlendSelect(shader, blendPort.get(), maskAlpha);
};



;// CONCATENATED MODULE: ./src/core/cgl/cgl_shader_lib.js




const ShaderLibMods = {
    "CGL.BLENDMODES": function ()
    {
        this.name = "blendmodes";
        this.srcHeadFrag = TextureEffect.getBlendCode();
    },
    "CGL.BLENDMODES3": function ()
    {
        this.name = "blendmodes3";
        this.srcHeadFrag = TextureEffect.getBlendCode(3);
    },

    "CGL.LUMINANCE": function ()
    {
        this.name = "luminance";
        this.srcHeadFrag = "".endl()
            + "float cgl_luminance(vec3 c)".endl()
            + "{".endl()
            + "    return dot(vec3(0.2126,0.7152,0.0722),c);".endl()
            + "}".endl();
    },


    // quite good random numbers, but somehow don't work in ANGLE
    "CGL.RANDOM_OLD": function ()
    {
        this.name = "randomNumber";
        this.srcHeadFrag = "".endl()
            + "float cgl_random(vec2 co)".endl()
            + "{".endl()
            + "    return fract(sin(dot(co.xy ,vec2(12.9898,4.1414))) * 432758.5453);".endl()
            + "}".endl()
            + "vec3 cgl_random3(vec2 co)".endl()
            + "{".endl()
            + "    return vec3( cgl_random(co),cgl_random(co+0.5711),cgl_random(co+1.5711));".endl()
            + "}";
    },


    // low quality generative ranodm numbers
    "CGL.RANDOM_LOW": function ()
    {
        this.name = "randomNumber";
        this.srcHeadFrag = "".endl()
            + "float cgl_random(vec2 co)".endl()
            + "{".endl()
            + "    return fract(sin(dot(co.xy ,vec2(12.9898,4.1414))) * 358.5453);".endl()
            + "}".endl()
            + "vec3 cgl_random3(vec2 co)".endl()
            + "{".endl()
            + "    return vec3( cgl_random(co),cgl_random(co+0.5711),cgl_random(co+1.5711));".endl()
            + "}";
    },

    // texture based random numbers
    "CGL.RANDOM_TEX": function ()
    {
        this.name = "randomNumbertex";
        this.srcHeadFrag = "".endl()
            + "UNI sampler2D CGLRNDTEX;".endl()
            + "float cgl_random(vec2 co)".endl()
            + "{".endl()
            + "    return texture(CGLRNDTEX,co*5711.0).r;".endl()
            + "}".endl()
            + "vec3 cgl_random3(vec2 co)".endl()
            + "{".endl()
            + "    return texture(CGLRNDTEX,co*5711.0).rgb;".endl()
            + "}";

        this.initUniforms = function (shader)
        {
            return [new Uniform(shader, "t", "CGLRNDTEX", 7)];
        };

        this.onBind = function (cgl, shader)
        {
            Texture.getRandomTexture(cgl);
            cgl.setTexture(7, Texture.getRandomTexture(cgl).tex);
        };
    },
};



;// CONCATENATED MODULE: ./src/core/cgl/cgl_utils.js
/** @namespace CGL */

/**
 * multiply to get radians from degree, e.g. `360 * CGL.DEG2RAD`
 * @const {Number}
 * @memberof CGL
 * @static
 */
const cgl_utils_DEG2RAD = Math.PI / 180.0;

/**
 * to get degrees from radians, e.g. `3.14 * CGL.RAD2DEG`
 * @const {number}
 * @memberof CGL
 */
const cgl_utils_RAD2DEG = 180.0 / Math.PI;

const onLoadingAssetsFinished = null; // deprecated / remove later

/**
 * get normalized mouse wheel delta (including browser specific adjustment)
 * @function getWheelDelta
 * @static
 * @memberof CGL
 * @param {MouseEvent} event
 * @return {Number} normalized delta
 */
const isWindows = window.navigator.userAgent.contains("Windows");
const getWheelDelta_ = function (event)
{
    let normalized;
    if (event.wheelDelta)
    {
        // chrome
        normalized = (event.wheelDelta % 120) - 0 == -0 ? event.wheelDelta / 120 : event.wheelDelta / 30;
        normalized *= -1.5;
        if (isWindows) normalized *= 2;
    }
    else
    {
        // firefox
        let d = event.deltaY;
        if (event.shiftKey) d = event.deltaX;
        const rawAmmount = d || event.detail;
        normalized = -(rawAmmount % 3 ? rawAmmount * 10 : rawAmmount / 3);
        normalized *= -3;
    }

    if (normalized > 20) normalized = 20;
    if (normalized < -20) normalized = -20;

    return normalized;
};

const getWheelSpeed = getWheelDelta_;
const getWheelDelta = getWheelDelta_;

// from https://github.com/lodash/lodash/blob/master/escape.js

const htmlEscapes = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    "\"": "&quot;",
    "'": "&#39;",
};

/** Used to match HTML entities and HTML characters. */
const reUnescapedHtml = /[&<>"']/g;
const reHasUnescapedHtml = RegExp(reUnescapedHtml.source);

/*  eslint-disable */
const escapeHTML = function(string)
{
    return string && reHasUnescapedHtml.test(string) ?
        string.replace(reUnescapedHtml, function(chr) { return htmlEscapes[chr]; })
        : string || "";
}
/* eslint-enable */

;// CONCATENATED MODULE: ./src/core/cg/cg_shader.js



class CgShader extends EventTarget
{
    constructor()
    {
        super();
        this.id = simpleId();
        this._isValid = true;
        this._defines = [];

        this._moduleNames = [];
        this._modules = [];
        this._moduleNumId = 0;
    }

    /**
     * easily enable/disable a define without a value
     * @function toggleDefine
     * @memberof Shader
     * @instance
     * @param {name} name
     * @param {any} enabled value or port
     */
    toggleDefine(name, enabled)
    {
        if (enabled && typeof (enabled) == "object" && enabled.addEventListener) // port
        {
            if (enabled.changeListener)enabled.removeEventListener(enabled.changeListener);

            enabled.onToggleDefine = (v) =>
            {
                this.toggleDefine(name, v);
            };

            enabled.changeListener = enabled.on("change", enabled.onToggleDefine);
            enabled = enabled.get();
        }

        if (enabled) this.define(name);
        else this.removeDefine(name);
    }

    /**
     * add a define to a shader, e.g.  #define DO_THIS_THAT 1
     * @function define
     * @memberof Shader
     * @instance
     * @param {String} name
     * @param {Any} value (can be empty)
     */
    define(name, value)
    {
        if (value === null || value === undefined) value = "";

        if (typeof (value) == "object") // port
        {
            value.removeEventListener("change", value.onDefineChange);
            value.onDefineChange = (v) =>
            {
                this.define(name, v);
            };
            value.on("change", value.onDefineChange);

            value = value.get();
        }


        for (let i = 0; i < this._defines.length; i++)
        {
            if (this._defines[i][0] == name && this._defines[i][1] == value) return;
            if (this._defines[i][0] == name)
            {
                this._defines[i][1] = value;
                this.setWhyCompile("define " + name + " " + value);

                this._needsRecompile = true;
                return;
            }
        }
        this.setWhyCompile("define " + name + " " + value);
        this._needsRecompile = true;
        this._defines.push([name, value]);
    }

    getDefines()
    {
        return this._defines;
    }

    getDefine(name)
    {
        for (let i = 0; i < this._defines.length; i++)
            if (this._defines[i][0] == name) return this._defines[i][1];
        return null;
    }

    /**
     * return true if shader has define
     * @function hasDefine
     * @memberof Shader
     * @instance
     * @param {String} name
     * @return {Boolean}
     */
    hasDefine(name)
    {
        for (let i = 0; i < this._defines.length; i++)
            if (this._defines[i][0] == name) return true;
    }

    /**
     * remove a define from a shader
     * @param {name} name
     * @function removeDefine
     * @memberof Shader
     * @instance
     */
    removeDefine(name)
    {
        for (let i = 0; i < this._defines.length; i++)
        {
            if (this._defines[i][0] == name)
            {
                this._defines.splice(i, 1);
                this._needsRecompile = true;

                this.setWhyCompile("define removed:" + name);

                return;
            }
        }
    }


    hasModule(modId)
    {
        for (let i = 0; i < this._modules.length; i++)
        {
            if (this._modules[i].id == modId) return true;
        }
        return false;
    }

    setModules(names)
    {
        this._moduleNames = names;
    }


    /**
     * remove a module from shader
     * @function removeModule
     * @memberof Shader
     * @instance
     * @param {shaderModule} mod the module to be removed
     */
    removeModule(mod)
    {
        for (let i = 0; i < this._modules.length; i++)
        {
            if (mod && mod.id)
            {
                if (this._modules[i].id == mod.id || !this._modules[i])
                {
                    let found = true;
                    while (found)
                    {
                        found = false;
                        for (let j = 0; j < this._uniforms.length; j++)
                        {
                            if (this._uniforms[j].getName().startsWith(mod.prefix))
                            {
                                this._uniforms.splice(j, 1);
                                found = true;
                                continue;
                            }
                        }
                    }

                    this._needsRecompile = true;
                    this.setWhyCompile("remove module " + mod.title);
                    this._modules.splice(i, 1);
                    break;
                }
            }
        }
    }


    getNumModules()
    {
        return this._modules.length;
    }


    getCurrentModules() { return this._modules; }


    /**
     * add a module
     * @function addModule
     * @memberof Shader
     * @instance
     * @param {shaderModule} mod the module to be added
     * @param {shaderModule} [sibling] sibling module, new module will share the same group
     */
    addModule(mod, sibling)
    {
        if (this.hasModule(mod.id)) return;
        if (!mod.id) mod.id = CABLES.simpleId();
        if (!mod.numId) mod.numId = this._moduleNumId;
        if (!mod.num)mod.num = this._modules.length;
        if (sibling && !sibling.group) sibling.group = simpleId();

        if (!mod.group)
            if (sibling) mod.group = sibling.group;
            else mod.group = simpleId();

        mod.prefix = "mod" + mod.group + "_";
        this._modules.push(mod);

        this._needsRecompile = true;
        this.setWhyCompile("add module " + mod.title);
        this._moduleNumId++;

        return mod;
    }

    getAttributeSrc(mod, srcHeadVert, srcVert)
    {
        if (mod.attributes)
            for (let k = 0; k < mod.attributes.length; k++)
            {
                const r = this._getAttrSrc(mod.attributes[k], false);
                if (r.srcHeadVert)srcHeadVert += r.srcHeadVert;
                if (r.srcVert)srcVert += r.srcVert;
            }

        return { "srcHeadVert": srcHeadVert, "srcVert": srcVert };
    }

    replaceModuleSrc()
    {
        let srcHeadVert = "";

        for (let j = 0; j < this._modules.length; j++)
        {
            const mod = this._modules[j];
            if (mod.name == this._moduleNames[i])
            {
                srcHeadVert += "\n//---- MOD: group:" + mod.group + ": idx:" + j + " - prfx:" + mod.prefix + " - " + mod.title + " ------\n";

                srcVert += "\n\n//---- MOD: " + mod.title + " / " + mod.priority + " ------\n";


                if (mod.getAttributeSrc)
                {
                    const r = getAttributeSrc(mod, srcHeadVert, srcVert);
                    if (r.srcHeadVert)srcHeadVert += r.srcHeadVert;
                    if (r.srcVert)srcVert += r.srcVert;
                }


                srcHeadVert += mod.srcHeadVert || "";
                srcVert += mod.srcBodyVert || "";

                srcHeadVert += "\n//---- end mod ------\n";

                srcVert += "\n//---- end mod ------\n";

                srcVert = srcVert.replace(/{{mod}}/g, mod.prefix);
                srcHeadVert = srcHeadVert.replace(/{{mod}}/g, mod.prefix);

                srcVert = srcVert.replace(/MOD_/g, mod.prefix);
                srcHeadVert = srcHeadVert.replace(/MOD_/g, mod.prefix);
            }
        }


        vs = vs.replace("{{" + this._moduleNames[i] + "}}", srcVert);
    }
}



;// CONCATENATED MODULE: ./src/core/cgl/cgl_shader_default_glsl.vert
/* harmony default export */ const cgl_shader_default_glsl = ("{{MODULES_HEAD}}\nIN vec3 vPosition; //!@\nIN vec2 attrTexCoord;\nIN vec3 attrVertNormal;\nIN vec3 attrTangent,attrBiTangent;\n\nIN float attrVertIndex;\n\nOUT vec2 texCoord;\nOUT vec3 norm;\nUNI mat4 projMatrix;\nUNI mat4 viewMatrix;\nUNI mat4 modelMatrix;\n\nvoid main()\n{\n    texCoord=attrTexCoord;\n    norm=attrVertNormal;\n    vec4 pos=vec4(vPosition,  1.0);\n    vec3 tangent=attrTangent;\n    vec3 bitangent=attrBiTangent;\n    mat4 mMatrix=modelMatrix;\n    gl_PointSize=10.0;\n\n    {{MODULE_VERTEX_POSITION}}\n\n    mat4 modelViewMatrix=viewMatrix*mMatrix;\n    {{MODULE_VERTEX_MODELVIEW}}\n\n    gl_Position = projMatrix * modelViewMatrix * pos;\n}\n");
;// CONCATENATED MODULE: ./src/core/cgl/cgl_shader.js









// ---------------------------------------------------------------------------


/*

proposal default shader variable names:

attrVertex - currently: vPosition
attrVertexIndex - currently: attrVertIndex
attrTexCoord
attrInstMat - currently: instMat
attrVertColor
attrTangent
attrBiTangent

uProjMatrix - currently: projMatrix
uModelMatrix - currently: modelMatrix
uNormalMatrix - currently: normalMatrix
uCamPosition - currently: camPos

*/


// ---------------------------------------------------------------------------

let materialIdCounter = 0;




function getDefaultVertexShader()
{
    return cgl_shader_default_glsl;
}


function getDefaultFragmentShader(r, g, b)
{
    if (r == undefined)
    {
        r = 0.5;
        g = 0.5;
        b = 0.5;
    }
    return ""
        .endl() + "IN vec2 texCoord;"
        .endl() + "{{MODULES_HEAD}}"
        .endl() + "void main()"
        .endl() + "{"
        .endl() + "    vec4 col=vec4(" + r + "," + g + "," + b + ",1.0);"
        .endl() + "    {{MODULE_COLOR}}"
        .endl() + "    outColor = col;"
        .endl() + "}";
};


/**
 * @class
 * @namespace external:CGL
 * @hideconstructor
 * @param _cgl
 * @param _name
 * @param _op
 * @example
 * var shader=new CGL.Shader(cgl,'MinimalMaterial');
 * shader.setSource(attachments.shader_vert,attachments.shader_frag);
 */
class Shader extends CgShader
{
    constructor (_cgl, _name, _op)
    {
        super();
        if (!_cgl) throw new Error("shader constructed without cgl " + _name);

        this._log = new Logger("cgl_shader");
        this._cgl = _cgl;

        if (!_name) this._log.stack("no shader name given");
        this._name = _name || "unknown";

        if (_op) this.opId = _op.id;
        this.glslVersion = 0;
        if (_cgl.glVersion > 1) this.glslVersion = 300;

        this._materialId = ++materialIdCounter;

        this._program = null;
        this._uniforms = [];
        this._drawBuffers = [true];

        this._needsRecompile = true;
        this._compileReason = "initial";

        this.ignoreMissingUniforms = false;
        this._projMatrixUniform = null;
        this._mvMatrixUniform = null;
        this._mMatrixUniform = null;
        this._vMatrixUniform = null;
        this._camPosUniform = null;
        this._normalMatrixUniform = null;
        this._inverseViewMatrixUniform = null;
        this._fromUserInteraction = false;

        this._attrVertexPos = -1;
        this.precision = _cgl.patch.config.glslPrecision || "highp";

        this._pMatrixState = -1;
        this._vMatrixState = -1;

        this._countMissingUniforms = 0;
        this._modGroupCount = 0; // not needed anymore...
        this._feedBackNames = [];
        this._attributes = [];

        this.glPrimitive = null;
        this.offScreenPass = false;
        this._extensions = [];
        this.srcVert = getDefaultVertexShader();
        this.srcFrag = getDefaultFragmentShader();
        this.lastCompile = 0;


        this._libs = [];
        this._structNames = [];
        this._structUniformNames = [];
        this._textureStackUni = [];
        this._textureStackTex = [];
        this._textureStackType = [];
        this._textureStackTexCgl = [];

        this._tempNormalMatrix = mat4.create();
        this._tempCamPosMatrix = mat4.create();
        this._tempInverseViewMatrix = mat4.create();
        this._tempInverseProjMatrix = mat4.create();

        this.setModules(["MODULE_VERTEX_POSITION", "MODULE_COLOR", "MODULE_BEGIN_FRAG", "MODULE_VERTEX_MODELVIEW"]);
    };







    isValid()
    {
        return this._isValid;
    };

    getCgl()
    {
        return this._cgl;
    };

    getName()
    {
        return this._name;
    };

    /**
     * enable an extension for the shader
     * @function enableExtension
     * @memberof Shader
     * @instance
     * @param name extension name
     */
    enableExtension(name)
    {
        this.setWhyCompile("enable extension " + name);
        this._needsRecompile = true;
        this._extensions.push(name);
    };

    getAttrVertexPos()
    {
        return this._attrVertexPos;
    };

    hasTextureUniforms()
    {
        for (let i = 0; i < this._uniforms.length; i++)
            if (this._uniforms[i].getType() == "t") return true;
        return false;
    };

    setWhyCompile(why)
    {
        this._compileReason = why;
    };

    /**
     * copy all uniform values from another shader
     * @function copyUniforms
     * @memberof Shader
     * @instance
     * @param origShader uniform values will be copied from this shader
     */
    copyUniformValues(origShader)
    {
        // console.log(origShader._uniforms);
        for (let i = 0; i < origShader._uniforms.length; i++)
        {
            if (!this._uniforms[i])
            {
                this._log.log("unknown uniform?!");
                continue;
            }

            // this._log.log(origShader._uniforms[i].getName());
            // this.getUniform(origShader._uniforms[i].)
            // this._uniforms[i].set(origShader._uniforms[i].getValue());


            // if (origShader._uniforms[i].getName().contains("pathPoints"))
            //     console.log("copyUniformValues", origShader._uniforms[i].getName(), origShader._uniforms[i].getValue());

            this.getUniform(origShader._uniforms[i].getName()).set(origShader._uniforms[i].getValue());
        }

        this.popTextures();
        for (let i = 0; i < origShader._textureStackUni.length; i++)
        {
            this._textureStackUni[i] = origShader._textureStackUni[i];
            this._textureStackTex[i] = origShader._textureStackTex[i];
            this._textureStackType[i] = origShader._textureStackType[i];
            this._textureStackTexCgl[i] = origShader._textureStackTexCgl[i];
        }

        // this._textureStackUni = [];
        // this._textureStackTex = [];
        // this._textureStackType = [];
        // this._textureStackTexCgl = [];
    };

    /**
     * copy current shader
     * @function copy
     * @memberof Shader
     * @instance
     * @returns newShader
     */
    copy()
    {
        const shader = new Shader(this._cgl, this._name + " copy");
        shader.setSource(this.srcVert, this.srcFrag);

        shader._modules = JSON.parse(JSON.stringify(this._modules));
        shader._defines = JSON.parse(JSON.stringify(this._defines));

        shader._modGroupCount = this._modGroupCount;
        shader._moduleNames = this._moduleNames;
        shader.glPrimitive = this.glPrimitive;
        shader.offScreenPass = this.offScreenPass;
        shader._extensions = this._extensions;
        shader.wireframe = this.wireframe;
        shader._attributes = this._attributes;

        for (let i = 0; i < this._uniforms.length; i++)
        {
            const u = this._uniforms[i].copy(shader);
            u.resetLoc();
        }

        this.setWhyCompile("copy");
        shader._needsRecompile = true;
        return shader;
    };


    /**
     * set shader source code
     * @function setSource
     * @memberof Shader
     * @instance
     * @param {String} srcVert
     * @param {String} srcFrag
     * @param {Bool} fromUserInteraction
     */
    setSource(srcVert, srcFrag, fromUserInteraction)
    {
        this._fromUserInteraction = fromUserInteraction;
        this.srcVert = srcVert;
        this.srcFrag = srcFrag;
        this.setWhyCompile("Source changed");
        this._needsRecompile = true;
        this._isValid = true;
    };

    _addLibs(src)
    {
        for (const id in ShaderLibMods)
        {
            if (src.contains(id))
            {
                const lib = new ShaderLibMods[id]();
                src = src.replace("{{" + id + "}}", lib.srcHeadFrag);
                this._libs.push(lib);
                if (lib.initUniforms)lib.initUniforms(this);
            }
        }

        return src;
    };

    createStructUniforms()
    {
        // * create structs
        let structStrFrag = "";
        let structStrVert = ""; // TODO: not used yet

        this._structNames = [];
        // * reset the arrays holding the value each recompile so we don't skip structs
        // * key value mapping so the same struct can be added twice (two times the same modifier)
        this._injectedStringsFrag = {};
        this._injectedStringsVert = {};

        this._structUniformNamesIndicesFrag = [];
        this._structUniformNamesIndicesVert = [];

        for (let i = 0; i < this._uniforms.length; i++)
        {
            // * only add uniforms to struct that are a member of a struct
            if (this._uniforms[i].isStructMember())
            {
                const injectionString = "{{INJECTION_POINT_STRUCT_" + this._uniforms[i]._structName + "}}";

                // * check if struct is not already part of shader
                if (!this._structNames.includes(this._uniforms[i]._structName))
                {
                    // * create struct definition with placeholder string to inject
                    const structDefinition = "struct "
                        + this._uniforms[i]._structName + " {".endl()
                        + injectionString
                        + "};".endl().endl();

                    if (this._uniforms[i].getShaderType() === "both" || this._uniforms[i].getShaderType() === "frag")
                        structStrFrag = structStrFrag.concat(structDefinition);

                    if (this._uniforms[i].getShaderType() === "both" || this._uniforms[i].getShaderType() === "vert")
                        structStrVert = structStrVert.concat(structDefinition);

                    this._structNames.push(this._uniforms[i]._structName);
                    this._injectedStringsFrag[this._uniforms[i]._structName] = [];
                    this._injectedStringsVert[this._uniforms[i]._structName] = [];
                }

                // * create member & comment
                let comment = "";
                if (this._uniforms[i].comment) comment = " // " + this._uniforms[i].comment;

                let stringToInsert = "";
                if (this._uniforms[i].getGlslTypeString() == undefined)stringToInsert += "//";
                stringToInsert += "  " + this._uniforms[i].getGlslTypeString()
                        + " " + this._uniforms[i]._propertyName + ";"
                        + comment;

                if (this._uniforms[i].getShaderType() === "both")
                {
                    // * inject member before {injectionString}
                    if (
                        !this._injectedStringsFrag[this._uniforms[i]._structName].contains(stringToInsert)
                    && !this._injectedStringsVert[this._uniforms[i]._structName].contains(stringToInsert))
                    {
                        const insertionIndexFrag = structStrFrag.lastIndexOf(injectionString);
                        const insertionIndexVert = structStrVert.lastIndexOf(injectionString);

                        structStrFrag =
                            structStrFrag.slice(0, insertionIndexFrag)
                            + stringToInsert + structStrFrag.slice(insertionIndexFrag - 1);

                        structStrVert =
                            structStrVert.slice(0, insertionIndexVert)
                            + stringToInsert + structStrVert.slice(insertionIndexVert - 1);

                        this._injectedStringsFrag[this._uniforms[i]._structName].push(stringToInsert);
                        this._injectedStringsVert[this._uniforms[i]._structName].push(stringToInsert);
                    }

                    if (!this._structUniformNamesIndicesFrag.includes(i)) this._structUniformNamesIndicesFrag.push(i);
                    if (!this._structUniformNamesIndicesVert.includes(i)) this._structUniformNamesIndicesVert.push(i);
                }
                else if (this._uniforms[i].getShaderType() === "frag")
                {
                    // * inject member before {injectionString}
                    if (!this._injectedStringsFrag[this._uniforms[i]._structName].includes(stringToInsert)) //
                    {
                        const insertionIndexFrag = structStrFrag.lastIndexOf(injectionString);

                        structStrFrag =
                            structStrFrag.slice(0, insertionIndexFrag)
                            + stringToInsert + structStrFrag.slice(insertionIndexFrag - 1);

                        this._injectedStringsFrag[this._uniforms[i]._structName].push(stringToInsert);
                    }

                    if (!this._structUniformNamesIndicesFrag.includes(i)) this._structUniformNamesIndicesFrag.push(i);
                }
                else if (this._uniforms[i].getShaderType() === "vert")
                {
                    // * inject member before {injectionString}
                    if (!this._injectedStringsVert[this._uniforms[i]._structName].includes(stringToInsert))
                    {
                        const insertionIndexVert = structStrVert.lastIndexOf(injectionString);

                        structStrVert =
                            structStrVert.slice(0, insertionIndexVert)
                            + stringToInsert + structStrVert.slice(insertionIndexVert - 1);

                        this._injectedStringsVert[this._uniforms[i]._structName].push(stringToInsert);
                    }

                    if (!this._structUniformNamesIndicesVert.includes(i)) this._structUniformNamesIndicesVert.push(i);
                }
            }
        }

        // * dedupe injected uni declarations
        this._uniDeclarationsFrag = [];
        this._uniDeclarationsVert = [];

        // * remove struct injection points and add uniform in fragment
        for (let i = 0; i < this._structUniformNamesIndicesFrag.length; i += 1)
        {
            const index = this._structUniformNamesIndicesFrag[i];
            const uniDeclarationString = "UNI " + this._uniforms[index]._structName + " " + this._uniforms[index]._structUniformName + ";".endl();

            if (!this._uniDeclarationsFrag.includes(uniDeclarationString))
            {
                const injectionString = "{{INJECTION_POINT_STRUCT_" + this._uniforms[index]._structName + "}}";

                structStrFrag = structStrFrag.replace(injectionString, "");
                structStrFrag += uniDeclarationString;

                this._uniDeclarationsFrag.push(uniDeclarationString);
            }
        }

        // * remove struct injection points and add uniform in vertex
        for (let i = 0; i < this._structUniformNamesIndicesVert.length; i += 1)
        {
            const index = this._structUniformNamesIndicesVert[i];
            const uniDeclarationString = "UNI " + this._uniforms[index]._structName + " " + this._uniforms[index]._structUniformName + ";".endl();

            if (!this._uniDeclarationsVert.includes(uniDeclarationString))
            {
                const injectionString = "{{INJECTION_POINT_STRUCT_" + this._uniforms[index]._structName + "}}";

                structStrVert = structStrVert.replace(injectionString, "");
                structStrVert += uniDeclarationString;
                this._uniDeclarationsVert.push(uniDeclarationString);
            }
        }

        return [structStrVert, structStrFrag];
    };

    _getAttrSrc(attr, firstLevel)
    {
        const r = {};
        if (attr.name && attr.type)
        {
            r.srcHeadVert = "";
            if (!firstLevel) r.srcHeadVert += "#ifndef ATTRIB_" + attr.name.endl();
            r.srcHeadVert += "#define ATTRIB_" + attr.name.endl();
            r.srcHeadVert += "IN " + attr.type + " " + attr.name + ";".endl();
            if (!firstLevel) r.srcHeadVert += "#endif".endl();

            if (attr.nameFrag)
            {
                r.srcHeadVert += "";
                if (!firstLevel) r.srcHeadVert += "#ifndef ATTRIB_" + attr.nameFrag.endl();
                r.srcHeadVert += "#define ATTRIB_" + attr.nameFrag.endl();
                r.srcHeadVert += "OUT " + attr.type + " " + attr.nameFrag + ";".endl();
                if (!firstLevel) r.srcHeadVert += "#endif".endl();

                r.srcVert = "".endl() + attr.nameFrag + "=" + attr.name + ";";

                r.srcHeadFrag = "";
                if (!firstLevel) r.srcHeadFrag += "#ifndef ATTRIB_" + attr.nameFrag.endl();
                r.srcHeadFrag += "#define ATTRIB_" + attr.nameFrag.endl();
                r.srcHeadFrag += "IN " + attr.type + " " + attr.nameFrag + ";".endl();
                if (!firstLevel) r.srcHeadFrag += "#endif".endl();
            }
        }
        return r;
    };

    compile()
    {
        if (this._cgl.aborted) return;
        const startTime = performance.now();



        this._cgl.profileData.profileShaderCompiles++;
        this._cgl.profileData.profileShaderCompileName = this._name + " [" + this._compileReason + "]";

        let extensionString = "";
        if (this._extensions)
            for (let i = 0; i < this._extensions.length; i++)
                extensionString += "#extension " + this._extensions[i] + " : enable".endl();

        let definesStr = "";
        if (this._defines.length) definesStr = "\n// cgl generated".endl();
        for (let i = 0; i < this._defines.length; i++)
            definesStr += "#define " + this._defines[i][0] + " " + this._defines[i][1] + "".endl();

        const structStrings = this.createStructUniforms();
        this._cgl.profileData.addHeavyEvent("shader compile", this._name + " [" + this._compileReason + "]");
        this._compileReason = "";



        if (this._uniforms)
        {
            // * we create an array of the uniform names to check our indices & an array to save them
            const uniNames = this._uniforms.map((uni) => { return uni._name; });
            const indicesToRemove = [];

            // * we go through our uniforms and check if the same name is contained somewhere further in the array
            // * if so, we add the current index to be removed later
            for (let i = 0; i < this._uniforms.length; i++)
            {
                const uni = this._uniforms[i];
                const nextIndex = uniNames.indexOf(uni._name, i + 1);
                if (nextIndex > -1) indicesToRemove.push(i);
            }

            // * after that, we go through the uniforms backwards (so we keep the order) and remove the indices
            // * also, we reset the locations of all the other valid uniforms
            for (let j = this._uniforms.length - 1; j >= 0; j -= 1)
            {
                if (indicesToRemove.includes(j)) this._uniforms.splice(j, 1);
                else this._uniforms[j].resetLoc();
            }
        }

        this._cgl.printError("uniform resets");

        if (this.hasTextureUniforms()) definesStr += "#define HAS_TEXTURES".endl();

        let vs = "";
        let fs = "";

        if (!this.srcFrag)
        {
            this._log.warn("[cgl shader] has no fragment source!", this._name, this);
            this.srcVert = getDefaultVertexShader();
            this.srcFrag = getDefaultFragmentShader();
            // return;
        }

        if (this.glslVersion == 300)
        {
            vs = "#version 300 es"
                .endl() + "// "
                .endl() + "// vertex shader " + this._name
                .endl() + "// "
                .endl() + "precision " + this.precision + " float;"
                .endl() + "precision " + this.precision + " sampler2D;"
                .endl() + ""
                .endl() + "#define WEBGL2"
                .endl() + "#define texture2D texture"
                .endl() + "#define UNI uniform"
                .endl() + "#define IN in"
                .endl() + "#define OUT out"
                .endl();

            fs = "#version 300 es"
                .endl() + "// "
                .endl() + "// fragment shader " + this._name
                .endl() + "// "
                .endl() + "precision " + this.precision + " float;"
                .endl() + "precision " + this.precision + " sampler2D;"
                .endl() + ""
                .endl() + "#define WEBGL2"
                .endl() + "#define texture2D texture"
                .endl() + "#define IN in"
                .endl() + "#define OUT out"
                .endl() + "#define UNI uniform"
                .endl() + "{{DRAWBUFFER}}"

                .endl();
        }
        else
        {
            fs = ""
                .endl() + "// "
                .endl() + "// fragment shader " + this._name
                .endl() + "// "
                .endl() + "#define WEBGL1"
                .endl() + "#define texture texture2D"
                .endl() + "#define outColor gl_FragColor"
                .endl() + "#define IN varying"
                .endl() + "#define UNI uniform"
                .endl();

            vs = ""
                .endl() + "// "
                .endl() + "// vertex shader " + this._name
                .endl() + "// "
                .endl() + "#define WEBGL1"
                .endl() + "#define texture texture2D"
                .endl() + "#define OUT varying"
                .endl() + "#define IN attribute"
                .endl() + "#define UNI uniform"
                .endl();
        }

        let uniformsStrVert = "\n// cgl generated".endl();
        let uniformsStrFrag = "\n// cgl generated".endl();


        fs += "\n// active mods: --------------- ";
        vs += "\n// active mods: --------------- ";

        let foundModsFrag = false;
        let foundModsVert = false;
        for (let i = 0; i < this._moduleNames.length; i++)
        {
            for (let j = 0; j < this._modules.length; j++)
            {
                if (this._modules[j].name == this._moduleNames[i])
                {
                    if (this._modules[j].srcBodyFrag || this._modules[j].srcHeadFrag)
                    {
                        foundModsFrag = true;
                        fs += "\n// " + i + "." + j + ". " + this._modules[j].title + " (" + this._modules[j].name + ")";
                    }
                    if (this._modules[j].srcBodyVert || this._modules[j].srcHeadVert)
                    {
                        vs += "\n// " + i + "." + j + ". " + this._modules[j].title + " (" + this._modules[j].name + ")";
                        foundModsVert = true;
                    }
                }
            }
        }
        if (!foundModsVert)fs += "\n// no mods used...";
        if (!foundModsFrag)fs += "\n// no mods used...";
        fs += "\n";
        vs += "\n";

        for (let i = 0; i < this._uniforms.length; i++)
        {
            if (this._uniforms[i].shaderType && !this._uniforms[i].isStructMember())
            {
                let uniStr = "";
                if (!this._uniforms[i].getGlslTypeString())uniStr += "// ";
                uniStr += "UNI " + this._uniforms[i].getGlslTypeString() + " " + this._uniforms[i].getName();
                let comment = "";
                if (this._uniforms[i].comment) comment = " // " + this._uniforms[i].comment;

                if (this._uniforms[i].shaderType == "vert" || this._uniforms[i].shaderType == "both")
                    if (!this.srcVert.contains(uniStr) && !this.srcVert.contains("uniform " + this._uniforms[i].getGlslTypeString() + " " + this._uniforms[i].getName()))
                        uniformsStrVert += uniStr + ";" + comment.endl();

                if (this._uniforms[i].shaderType == "frag" || this._uniforms[i].shaderType == "both")
                    if (!this.srcFrag.contains(uniStr) && !this.srcFrag.contains("uniform " + this._uniforms[i].getGlslTypeString() + " " + this._uniforms[i].getName()))
                        uniformsStrFrag += uniStr + ";" + comment.endl();
            }
        }


        let countUniFrag = 0;
        let countUniVert = 0;
        for (let i = 0; i < this._uniforms.length; i++)
        {
            if (this._uniforms[i].shaderType && !this._uniforms[i].isStructMember())
            {
                if (this._uniforms[i].shaderType == "vert" || this._uniforms[i].shaderType == "both") countUniVert++;
                if (this._uniforms[i].shaderType == "frag" || this._uniforms[i].shaderType == "both") countUniFrag++;
            }
        }
        if (countUniFrag >= this._cgl.maxUniformsFrag) this._log.warn("[cgl_shader] num uniforms frag: " + countUniFrag + " / " + this._cgl.maxUniformsFrag);
        if (countUniVert >= this._cgl.maxUniformsVert) this._log.warn("[cgl_shader] num uniforms vert: " + countUniVert + " / " + this._cgl.maxUniformsVert);


        if (!fs.contains("precision")) fs = "precision " + this.precision + " float;".endl() + fs;
        if (!vs.contains("precision")) vs = "precision " + this.precision + " float;".endl() + vs;
        if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent))
        {
            fs += "#define MOBILE".endl();
            vs += "#define MOBILE".endl();
        }
        vs = extensionString + vs + definesStr + structStrings[0] + uniformsStrVert + "\n// -- \n" + this.srcVert;
        fs = extensionString + fs + definesStr + structStrings[1] + uniformsStrFrag + "\n// -- \n" + this.srcFrag;


        let srcHeadVert = "";
        let srcHeadFrag = "";

        // testing if this breaks things...
        // this._modules.sort(function (a, b)
        // {
        //     return a.group - b.group;
        // });

        this._modules.sort(function (a, b)
        {
            return a.priority || 0 - b.priority || 0;
        });


        let addedAttribs = false;

        for (let i = 0; i < this._moduleNames.length; i++)
        {
            let srcVert = "";
            let srcFrag = "";

            if (!addedAttribs)
            {
                addedAttribs = true;

                for (let k = 0; k < this._attributes.length; k++)
                {
                    const r = this._getAttrSrc(this._attributes[k], true);
                    if (r.srcHeadVert)srcHeadVert += r.srcHeadVert;
                    if (r.srcVert)srcVert += r.srcVert;
                    if (r.srcHeadFrag)srcHeadFrag += r.srcHeadFrag;
                }
            }

            for (let j = 0; j < this._modules.length; j++)
            {
                const mod = this._modules[j];
                if (mod.name == this._moduleNames[i])
                {
                    srcHeadVert += "\n//---- MOD: group:" + mod.group + ": idx:" + j + " - prfx:" + mod.prefix + " - " + mod.title + " ------\n";
                    srcHeadFrag += "\n//---- MOD: group:" + mod.group + ": idx:" + j + " - prfx:" + mod.prefix + " - " + mod.title + " ------\n";

                    srcVert += "\n\n//---- MOD: " + mod.title + " / " + mod.priority + " ------\n";
                    srcFrag += "\n\n//---- MOD: " + mod.title + " / " + mod.priority + " ------\n";

                    if (mod.attributes)
                        for (let k = 0; k < mod.attributes.length; k++)
                        {
                            const r = this._getAttrSrc(mod.attributes[k], false);
                            if (r.srcHeadVert)srcHeadVert += r.srcHeadVert;
                            if (r.srcVert)srcVert += r.srcVert;
                            if (r.srcHeadFrag)srcHeadFrag += r.srcHeadFrag;
                        }

                    srcHeadVert += mod.srcHeadVert || "";
                    srcHeadFrag += mod.srcHeadFrag || "";
                    srcVert += mod.srcBodyVert || "";
                    srcFrag += mod.srcBodyFrag || "";

                    srcHeadVert += "\n//---- end mod ------\n";
                    srcHeadFrag += "\n//---- end mod ------\n";

                    srcVert += "\n//---- end mod ------\n";
                    srcFrag += "\n//---- end mod ------\n";

                    srcVert = srcVert.replace(/{{mod}}/g, mod.prefix);
                    srcFrag = srcFrag.replace(/{{mod}}/g, mod.prefix);
                    srcHeadVert = srcHeadVert.replace(/{{mod}}/g, mod.prefix);
                    srcHeadFrag = srcHeadFrag.replace(/{{mod}}/g, mod.prefix);

                    srcVert = srcVert.replace(/MOD_/g, mod.prefix);
                    srcFrag = srcFrag.replace(/MOD_/g, mod.prefix);
                    srcHeadVert = srcHeadVert.replace(/MOD_/g, mod.prefix);
                    srcHeadFrag = srcHeadFrag.replace(/MOD_/g, mod.prefix);
                }
            }


            vs = vs.replace("{{" + this._moduleNames[i] + "}}", srcVert);
            fs = fs.replace("{{" + this._moduleNames[i] + "}}", srcFrag);
        }


        vs = vs.replace("{{MODULES_HEAD}}", srcHeadVert);
        fs = fs.replace("{{MODULES_HEAD}}", srcHeadFrag);


        vs = this._addLibs(vs);
        fs = this._addLibs(fs);


        // SETUP draw buffers / multi texture render targets

        let drawBufferStr = "";
        for (let i = 0; i < 16; i++)
            if (fs.contains("outColor" + i)) this._drawBuffers[i] = true;

        if (this._drawBuffers.length == 1)
        {
            drawBufferStr = "out vec4 outColor;".endl();
            drawBufferStr += "#define gl_FragColor outColor".endl();
        }
        else
        {
            drawBufferStr += "#define MULTI_COLORTARGETS".endl();
            drawBufferStr += "vec4 outColor;".endl();

            let count = 0;
            for (let i = 0; i < this._drawBuffers.length; i++)
            {
                if (count == 0) drawBufferStr += "#define gl_FragColor outColor" + i + "".endl();
                drawBufferStr += "layout(location = " + i + ") out vec4 outColor" + i + ";".endl();
                count++;
            }
        }

        fs = fs.replace("{{DRAWBUFFER}}", drawBufferStr);
        // //////


        if (!this._program)
        {
            this._program = this._createProgram(vs, fs);
        }
        else
        {
            // this.vshader=createShader(vs, gl.VERTEX_SHADER, this.vshader );
            // this.fshader=createShader(fs, gl.FRAGMENT_SHADER, this.fshader );
            // linkProgram(program);
            this._program = this._createProgram(vs, fs);

            this._projMatrixUniform = null;

            for (let i = 0; i < this._uniforms.length; i++) this._uniforms[i].resetLoc();
        }

        this.finalShaderFrag = fs;
        this.finalShaderVert = vs;


        MESH.lastMesh = null;
        MESH.lastShader = null;

        this._countMissingUniforms = 0;
        this._needsRecompile = false;
        this.lastCompile = now();

        // this._cgl.printError("shader compile");

        this._cgl.profileData.shaderCompileTime += performance.now() - startTime;
    };

    hasChanged()
    {
        return this._needsRecompile;
    }


    bind()
    {
        if (!this._isValid || this._cgl.aborted) return;

        MESH.lastShader = this;

        if (!this._program || this._needsRecompile) this.compile();
        if (!this._isValid) return;

        if (!this._projMatrixUniform && !this.ignoreMissingUniforms)
        {
            this._countMissingUniforms++;
            // if (this._countMissingUniforms == 10)console.log("stopping getlocation of missing uniforms...", this._name);
            if (this._countMissingUniforms < 10)
            {
                this._projMatrixUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_PROJMAT);
                this._attrVertexPos = this._cgl.glGetAttribLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_VERTEX_POSITION);
                this._mvMatrixUniform = this._cgl.gl.getUniformLocation(this._program, "mvMatrix");
                this._vMatrixUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_VIEWMAT);
                this._mMatrixUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_MODELMAT);
                this._camPosUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_VIEWPOS);
                this._normalMatrixUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_NORMALMAT);
                this._inverseViewMatrixUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_INVVIEWMAT);
                this._inverseProjMatrixUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_INVPROJMAT);
                this._materialIdUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_MATERIALID);
                this._objectIdUniform = this._cgl.gl.getUniformLocation(this._program, constants_CONSTANTS.SHADER.SHADERVAR_UNI_OBJECTID);

                for (let i = 0; i < this._uniforms.length; i++) this._uniforms[i].needsUpdate = true;
            }
        }


        if (this._cgl.currentProgram != this._program)
        {
            this._cgl.profileData.profileShaderBinds++;
            this._cgl.gl.useProgram(this._program);
            this._cgl.currentProgram = this._program;
        }

        for (let i = 0; i < this._uniforms.length; i++)
            if (this._uniforms[i].needsUpdate) this._uniforms[i].updateValue();

        if (this._pMatrixState != this._cgl.getProjectionMatrixStateCount())
        {
            this._pMatrixState = this._cgl.getProjectionMatrixStateCount();
            this._cgl.gl.uniformMatrix4fv(this._projMatrixUniform, false, this._cgl.pMatrix);
            this._cgl.profileData.profileMVPMatrixCount++;
        }

        if (this._objectIdUniform)
            this._cgl.gl.uniform1f(this._objectIdUniform, ++this._cgl.tempData.objectIdCounter);

        if (this._materialIdUniform)
            this._cgl.gl.uniform1f(this._materialIdUniform, this._materialId);

        if (this._vMatrixUniform)
        {
            if (this._vMatrixState != this._cgl.getViewMatrixStateCount())
            {
                this._cgl.gl.uniformMatrix4fv(this._vMatrixUniform, false, this._cgl.vMatrix);
                this._cgl.profileData.profileMVPMatrixCount++;
                this._vMatrixState = this._cgl.getViewMatrixStateCount();

                if (this._inverseViewMatrixUniform)
                {
                    mat4.invert(this._tempInverseViewMatrix, this._cgl.vMatrix);
                    this._cgl.gl.uniformMatrix4fv(this._inverseViewMatrixUniform, false, this._tempInverseViewMatrix);
                    this._cgl.profileData.profileMVPMatrixCount++;
                }
                if (this._inverseProjMatrixUniform)
                {
                    mat4.invert(this._tempInverseProjMatrix, this._cgl.pMatrix);
                    this._cgl.gl.uniformMatrix4fv(this._inverseProjMatrixUniform, false, this._tempInverseProjMatrix);
                    this._cgl.profileData.profileMVPMatrixCount++;
                }
            }
            this._cgl.gl.uniformMatrix4fv(this._mMatrixUniform, false, this._cgl.mMatrix);
            this._cgl.profileData.profileMVPMatrixCount++;

            if (this._camPosUniform)
            {
                mat4.invert(this._tempCamPosMatrix, this._cgl.vMatrix);
                this._cgl.gl.uniform3f(this._camPosUniform, this._tempCamPosMatrix[12], this._tempCamPosMatrix[13], this._tempCamPosMatrix[14]);
                this._cgl.profileData.profileMVPMatrixCount++;
            }
        }
        else
        {
            // mvmatrix deprecated....
            const tempmv = mat4.create();

            mat4.mul(tempmv, this._cgl.vMatrix, this._cgl.mMatrix);
            this._cgl.gl.uniformMatrix4fv(this._mvMatrixUniform, false, tempmv);
            this._cgl.profileData.profileMVPMatrixCount++;
        }

        if (this._normalMatrixUniform)
        {
            // mat4.mul(this._tempNormalMatrix, this._cgl.vMatrix, this._cgl.mMatrix);
            mat4.invert(this._tempNormalMatrix, this._cgl.mMatrix);
            mat4.transpose(this._tempNormalMatrix, this._tempNormalMatrix);

            this._cgl.gl.uniformMatrix4fv(this._normalMatrixUniform, false, this._tempNormalMatrix);
            this._cgl.profileData.profileMVPMatrixCount++;
        }

        for (let i = 0; i < this._libs.length; i++)
        {
            if (this._libs[i].onBind) this._libs[i].onBind.bind(this._libs[i])(this._cgl, this);
        }

        this._bindTextures();

        return this._isValid;
    };

    unBind()
    {
    };


    dispose()
    {
        this._cgl.gl.deleteProgram(this._program);
    };

    needsRecompile()
    {
        return this._needsRecompile;
    };

    setDrawBuffers(arr)
    {
        console.log("useless drawbuffers...?!");
        // if (this._drawBuffers.length !== arr.length)
        // {
        //     this._drawBuffers = arr;
        //     this._needsRecompile = true;
        //     this.setWhyCompile("setDrawBuffers");
        //     return;
        // }
        // for (let i = 0; i < arr.length; i++)
        // {
        //     if (arr[i] !== this._drawBuffers[i])
        //     {
        //         this._drawBuffers = arr;
        //         this._needsRecompile = true;
        //         this.setWhyCompile("setDrawBuffers");
        //         return;
        //     }
        // }
    };

    getUniforms()
    {
        return this._uniforms;
    };

    getUniform(name)
    {
        for (let i = 0; i < this._uniforms.length; i++)
            if (this._uniforms[i].getName() == name)
                return this._uniforms[i];
        return null;
    };

    removeAllUniforms()
    {
        this._uniforms = [];
        // for (let i = 0; i < this._uniforms.length; i++)
        //     this.removeUniform(this._uniforms[i].name);
    };

    removeUniform(name)
    {
        for (let i = 0; i < this._uniforms.length; i++)
        {
            if (this._uniforms[i].getName() == name)
            {
                this._uniforms.splice(i, 1);
            }
        }
        this._needsRecompile = true;
        this.setWhyCompile("remove uniform " + name);
    };


    _addUniform(uni)
    {
        this._uniforms.push(uni);
        this.setWhyCompile("add uniform " + name);
        this._needsRecompile = true;
    };

    /**
     * add a uniform to the fragment shader
     * @param {String} type ['f','t', etc]
     * @param {String} name
     * @param {any} valueOrPort value or port
     * @param p2
     * @param p3
     * @param p4
     * @memberof Shader
     * @instance
     * @function addUniformFrag
     * @returns {CGL.Uniform}
     */
    addUniformFrag(type, name, valueOrPort, p2, p3, p4)
    {
        const uni = new CGL.Uniform(this, type, name, valueOrPort, p2, p3, p4);
        uni.shaderType = "frag";
        return uni;
    };

    /**
     * add a uniform to the vertex shader
     * @param {String} type ['f','t', etc]
     * @param {String} name
     * @param {any} valueOrPort value or port
     * @param p2
     * @param p3
     * @param p4
     * @memberof Shader
     * @instance
     * @function addUniformVert
     * @returns {CGL.Uniform}
     */
    addUniformVert(type, name, valueOrPort, p2, p3, p4)
    {
        const uni = new CGL.Uniform(this, type, name, valueOrPort, p2, p3, p4);
        uni.shaderType = "vert";
        return uni;
    };
    /**
     * add a uniform to both shaders
     * @param {String} type ['f','t', etc]
     * @param {String} name
     * @param {any} valueOrPort value or port
     * @param p2
     * @param p3
     * @param p4
     * @memberof Shader
     * @instance
     * @function addUniformBoth
     * @returns {CGL.Uniform}
     */
    addUniformBoth(type, name, valueOrPort, p2, p3, p4)
    {
        const uni = new CGL.Uniform(this, type, name, valueOrPort, p2, p3, p4);
        uni.shaderType = "both";
        return uni;
    };

    /**
     * add a struct & its uniforms to the fragment shader
     * @param {String} structName name of the struct, i.e.: LightStruct
     * @param {String} uniformName name of the struct uniform in the shader, i.e.: lightUni
     * @param {Array} members array of objects containing the struct members. see example for structure

     * @memberof Shader
     * @instance
     * @function addUniformStructFrag
     * @returns {Object}
     * @example
     * const shader = new CGL.Shader(cgl, 'MinimalMaterial');
     * shader.setSource(attachments.shader_vert, attachments.shader_frag);
     * shader.addUniformStructFrag("Light", "uniformLight", [
     * { "type": "3f", "name": "position", "v1": null },
     * { "type": "4f", "name": "color", "v1": inR, v2: inG, v3: inB, v4: inAlpha }
     * ]);
     */
    addUniformStructFrag(structName, uniformName, members)
    {
        const uniforms = {};

        if (!members) return uniforms;

        for (let i = 0; i < members.length; i += 1)
        {
            const member = members[i];
            if (!this.hasUniform(uniformName + "." + member.name))
            {
                const uni = new CGL.Uniform(this, member.type, uniformName + "." + member.name, member.v1, member.v2, member.v3, member.v4, uniformName, structName, member.name);
                uni.shaderType = "frag";
                uniforms[uniformName + "." + member.name] = uni;
            }
        }

        return uniforms;
    };

    /**
     * add a struct & its uniforms to the vertex shader
     * @param {String} structName name of the struct, i.e.: LightStruct
     * @param {String} uniformName name of the struct uniform in the shader, i.e.: lightUni
     * @param {Array} members array of objects containing the struct members. see example for structure

     * @memberof Shader
     * @instance
     * @function addUniformStructVert
     * @returns {CGL.Uniform}
     * @example
     * const shader = new CGL.Shader(cgl, 'MinimalMaterial');
     * shader.setSource(attachments.shader_vert, attachments.shader_frag);
     * shader.addUniformStructVert("Light", "uniformLight", [
     * { "type": "3f", "name": "position", "v1": null },
     * { "type": "4f", "name": "color", "v1": inR, v2: inG, v3: inB, v4: inAlpha }
     * ]);
     */
    addUniformStructVert(structName, uniformName, members)
    {
        const uniforms = {};

        if (!members) return uniforms;

        for (let i = 0; i < members.length; i += 1)
        {
            const member = members[i];
            if (!this.hasUniform(uniformName + "." + member.name))
            {
                const uni = new CGL.Uniform(this, member.type, uniformName + "." + member.name, member.v1, member.v2, member.v3, member.v4, uniformName, structName, member.name);
                uni.shaderType = "vert";
                uniforms[uniformName + "." + member.name] = uni;
            }
        }

        return uniforms;
    };

    /**
     * add a struct & its uniforms to the both shaders. PLEASE NOTE: it is not possible to add the same struct to both shaders when it contains ANY integer members.
     * @param {String} structName name of the struct, i.e.: LightStruct
     * @param {String} uniformName name of the struct uniform in the shader, i.e.: lightUni
     * @param {Array} members array of objects containing the struct members. see example for structure

     * @memberof Shader
     * @instance
     * @function addUniformStructBoth
     * @returns {Object}
     * @example
     * const shader = new CGL.Shader(cgl, 'MinimalMaterial');
     * shader.setSource(attachments.shader_vert, attachments.shader_frag);
     * shader.addUniformStructBoth("Light", "uniformLight", [
     * { "type": "3f", "name": "position", "v1": null },
     * { "type": "4f", "name": "color", "v1": inR, v2: inG, v3: inB, v4: inAlpha }
     * ]);
     */
    addUniformStructBoth(structName, uniformName, members)
    {
        const uniforms = {};

        if (!members) return uniforms;

        for (let i = 0; i < members.length; i += 1)
        {
            const member = members[i];
            if ((member.type === "2i" || member.type === "i" || member.type === "3i"))
                this._log.error("Adding an integer struct member to both shaders can potentially error. Please use different structs for each shader. Error occured in struct:", structName, " with member:", member.name, " of type:", member.type, ".");
            if (!this.hasUniform(uniformName + "." + member.name))
            {
                const uni = new CGL.Uniform(this, member.type, uniformName + "." + member.name, member.v1, member.v2, member.v3, member.v4, uniformName, structName, member.name);
                uni.shaderType = "both";
                uniforms[uniformName + "." + member.name] = uni;
            }
        }

        return uniforms;
    };

    hasUniform(name)
    {
        for (let i = 0; i < this._uniforms.length; i++)
        {
            if (this._uniforms[i].getName() == name) return true;
        }
        return false;
    };

    _createProgram(vstr, fstr)
    {
        this._cgl.printError("before _createprogram");

        const program = this._cgl.gl.createProgram();

        this.vshader = Shader.createShader(this._cgl, vstr, this._cgl.gl.VERTEX_SHADER, this);
        this.fshader = Shader.createShader(this._cgl, fstr, this._cgl.gl.FRAGMENT_SHADER, this);


        if (this.vshader && this.fshader)
        {
            this._cgl.gl.attachShader(program, this.vshader);
            this._cgl.gl.attachShader(program, this.fshader);

            this._linkProgram(program, vstr, fstr);
        }
        else
        {
            this._isValid = false;
            this._cgl.printError("shader _createProgram");
            this._log.error("could not link shaderprogram");
            return null;
        }

        this._cgl.printError("shader _createProgram");
        return program;
    };

    hasErrors()
    {
        return this._hasErrors;
    };

    _linkProgram(program, vstr, fstr)
    {
        this._cgl.printError("before _linkprogram");

        if (this._feedBackNames.length > 0)
        {
            this._cgl.gl.transformFeedbackVaryings(program, this._feedBackNames, this._cgl.gl.SEPARATE_ATTRIBS);
            // INTERLEAVED_ATTRIBS
            // SEPARATE_ATTRIBS
        }

        this._cgl.gl.linkProgram(program);
        this._cgl.printError("gl.linkprogram");
        this._isValid = true;

        this._hasErrors = false;

        if (this._cgl.patch.config.glValidateShader !== false)
        {
            this._cgl.gl.validateProgram(program);

            if (!this._cgl.gl.getProgramParameter(program, this._cgl.gl.VALIDATE_STATUS))
            {
                // validation failed
                console.log("shaderprogram validation failed...");
                console.log(this._name + " programinfo: ", this._cgl.gl.getProgramInfoLog(program));
            }

            if (!this._cgl.gl.getProgramParameter(program, this._cgl.gl.LINK_STATUS))
            {
                this._hasErrors = true;

                const infoLogFrag = this._cgl.gl.getShaderInfoLog(this.fshader);
                const infoLogVert = this._cgl.gl.getShaderInfoLog(this.vshader);

                if (infoLogFrag) this._log.warn(this._cgl.gl.getShaderInfoLog(this.fshader));
                if (infoLogVert) this._log.warn(this._cgl.gl.getShaderInfoLog(this.vshader));

                this._log.error(this._name + " shader linking fail...");

                console.log(this._name + " programinfo: ", this._cgl.gl.getProgramInfoLog(program));
                console.log(this);
                this._isValid = false;

                this._name = "errorshader";
                this.setSource(Shader.getDefaultVertexShader(), Shader.getErrorFragmentShader());
                this._cgl.printError("shader link err");
            }
        }
    };

    getProgram()
    {
        return this._program;
    };

    setFeedbackNames(names)
    {
        this.setWhyCompile("setFeedbackNames");
        this._needsRecompile = true;
        this._feedBackNames = names;
    };

    // getDefaultVertexShader()
    // {
    //     return defaultShaderSrcVert;
    // }

    // getDefaultFragmentShader()
    // {
    //     return this.getDefaultFragmentShader()
    // }


    /**
      * adds attribute definition to shader header without colliding with other shader modules...
     * when attrFrag is defined, vertex shader will output this attribute to the fragment shader
     * @function
     * @memberof Shader
     * @instance
     * @param {Object} attr {type:x,name:x,[nameFrag:x]}
     * @return {Object}
     */
    addAttribute = function (attr)
    {
        for (let i = 0; i < this._attributes.length; i++)
        {
            if (this._attributes[i].name == attr.name && this._attributes[i].nameFrag == attr.nameFrag) return;
        }
        this._attributes.push(attr);
        this._needsRecompile = true;
        this.setWhyCompile("addAttribute");
    };

    bindTextures()
    {
        this._bindTextures();
    }
    _bindTextures()
    {
        if (this._textureStackTex.length > this._cgl.maxTextureUnits)
        {
            this._log.warn("[shader._bindTextures] too many textures bound", this._textureStackTex.length + "/" + this._cgl.maxTextureUnits);
        }

        // for (let i = this._textureStackTex.length + 1; i < this._cgl.maxTextureUnits; i++) this._cgl.setTexture(i, null);

        for (let i = 0; i < this._textureStackTex.length; i++)
        {
            // console.log(this._textureStackTex.length, i);
            if (!this._textureStackTex[i] && !this._textureStackTexCgl[i])
            {
                this._log.warn("no texture for pushtexture", this._name);
            }
            else
            {
                let t = this._textureStackTex[i];
                if (this._textureStackTexCgl[i])
                {
                    t = this._textureStackTexCgl[i].tex || CGL.Texture.getEmptyTexture(this._cgl).tex;
                }

                let bindOk = true;

                if (!this._textureStackUni[i])
                {
                    // throw(new Error('no uniform given to texturestack'));
                    this._log.warn("no uniform for pushtexture", this._name);
                    bindOk = this._cgl.setTexture(i, t, this._textureStackType[i]);
                }
                else
                {
                    this._textureStackUni[i].setValue(i);
                    bindOk = this._cgl.setTexture(i, t, this._textureStackType[i]);

                    // console.log(bindOk, i, t, this._textureStackType[i]);
                }
                if (!bindOk) console.warn("tex bind failed", this.getName(), this._textureStackUni[i]);
            }
        }
    };

    setUniformTexture = function (uni, tex)
    {
        tex = tex || CGL.Texture.getTempTexture(this._cgl);
        for (let i = 0; i < this._textureStackUni.length; i++)
            if (this._textureStackUni[i] == uni)
            {
                const old = this._textureStackTex[i] || this._textureStackTexCgl[i];
                if (tex.hasOwnProperty("tex"))
                {
                    this._textureStackTexCgl[i] = tex;
                    this._textureStackTex[i] = null;
                }
                else
                {
                    this._textureStackTexCgl[i] = null;
                    this._textureStackTex[i] = tex;
                }

                // this._textureStackTex[i] = tex;
                // this._cgl.setTexture(i, tex, this._textureStackType[i]);
                return old;
            }
        return null;
    };

    /**
     * push a texture on the stack. those textures will be bound when binding the shader. texture slots are automatically set
     * @param {uniform} uniform texture uniform
     * @param {texture} t texture
     * @param {type} type texture type, can be ignored when TEXTURE_2D
     * @function pushTexture
     * @memberof Shader
     * @instance
     */
    pushTexture = function (uniform, t, type)
    {
        if (!uniform)
        {
            // console.log("pushtexture: no uniform given to texturestack", "shader:"+this._name,uniform,t,type);
            return;
        }
        if (!t)
        {
            // if(uniform)this._log.warn("pushtexture: no tex","shader:"+this._name," uniform:"+uniform.name);
            return;
        }
        if (!t.hasOwnProperty("tex") && !(t instanceof WebGLTexture))
        {
            this._log.warn(new Error("invalid texture").stack);

            this._log.warn("[cgl_shader] invalid texture...", t);
            return;
        }

        this._textureStackUni.push(uniform);

        if (t.hasOwnProperty("tex"))
        {
            this._textureStackTexCgl.push(t);
            this._textureStackTex.push(null);
        }
        else
        {
            this._textureStackTexCgl.push(null);
            this._textureStackTex.push(t);
        }

        this._textureStackType.push(type);
    };

    /**
     * pop last texture
     * @function popTexture
     * @memberof Shader
     * @instance
     */
    popTexture = function ()
    {
        this._textureStackUni.pop();
        this._textureStackTex.pop();
        this._textureStackTexCgl.pop();
        this._textureStackType.pop();
    };

    /**
     * pop all textures
     * @function popTextures
     * @memberof Shader
     * @instance
     */
    popTextures = function ()
    {
        this._textureStackTex.length =
        this._textureStackTexCgl.length =
        this._textureStackType.length =
        this._textureStackUni.length = 0;
    };

    getMaterialId()
    {
        return this._materialId;
    };

    getInfo()
    {
        const info = {};
        info.name = this._name;
        // info.modules = JSON.parse(JSON.stringify(this._modules));
        // info.defines = JSON.parse(JSON.stringify(this._defines));
        info.defines = this.getDefines();
        info.hasErrors = this.hasErrors();

        return info;
    };


    getDefaultFragmentShader=function(r,g,b,a)
    {
        return getDefaultFragmentShader(r,g,b,a);
    }

    getDefaultVertexShader=function()
    {
        return getDefaultVertexShader();
    }


}

























// --------------------------

Shader.getDefaultVertexShader=getDefaultVertexShader;
Shader.getDefaultFragmentShader=getDefaultFragmentShader;


Shader.getErrorFragmentShader = function ()
{
    return ""
        .endl() + "void main()"
        .endl() + "{"
        .endl() + "   float g=mod((gl_FragCoord.y+gl_FragCoord.x),50.0)/50.0;"
        .endl() + "   g= step(0.1,g);"
        .endl() + "   outColor = vec4( g+0.5, 0.0, 0.0, 1.0);"
        .endl() + "}";
};

Shader.createShader = function (cgl, str, type, cglShader)
{
    if (cgl.aborted) return;

    // cgl.printError("[Shader.createShader] ", cglShader._name);

    function getBadLines(infoLog)
    {
        const basLines = [];
        const lines = infoLog.split("\n");
        for (const i in lines)
        {
            const divide = lines[i].split(":");
            if (parseInt(divide[2], 10)) basLines.push(parseInt(divide[2], 10));
        }
        return basLines;
    }


    const shader = cgl.gl.createShader(type);
    cgl.gl.shaderSource(shader, str);
    cgl.gl.compileShader(shader);

    if (!cgl.gl.getShaderParameter(shader, cgl.gl.COMPILE_STATUS))
    {
        let infoLog = cgl.gl.getShaderInfoLog(shader);
        if (!infoLog)
        {
            console.warn("empty shader info log", this._name);
            return;
        }


        const badLines = getBadLines(infoLog);
        let htmlWarning = "<pre style=\"margin-bottom:0px;\"><code class=\"shaderErrorCode language-glsl\" style=\"padding-bottom:0px;max-height: initial;max-width: initial;\">";
        const lines = str.match(/^.*((\r\n|\n|\r)|$)/gm);

        if (!cgl.aborted && infoLog)
        {
            if (type == cgl.gl.VERTEX_SHADER) console.log("VERTEX_SHADER");
            if (type == cgl.gl.FRAGMENT_SHADER) console.log("FRAGMENT_SHADER");

            for (const i in lines)
            {
                const j = parseInt(i, 10) + 1;
                const line = j + ": " + lines[i];

                let isBadLine = false;
                for (const bj in badLines)
                    if (badLines[bj] == j) isBadLine = true;

                if (isBadLine)
                {
                    htmlWarning += "</code></pre>";
                    htmlWarning += "<pre style=\"margin:0\"><code class=\"language-glsl\" style=\"background-color:#660000;padding-top:0px;padding-bottom:0px\">";

                    cglShader._log.log("bad line: `" + line + "`");
                }
                htmlWarning += escapeHTML(line);

                if (isBadLine)
                {
                    htmlWarning += "</code></pre>";
                    htmlWarning += "<pre style=\"margin:0\"><code class=\"language-glsl\" style=\";padding-top:0px;padding-bottom:0px\">";
                }
            }
        }

        infoLog = infoLog.replace(/\n/g, "<br/>");
        if (cgl.patch.isEditorMode())console.log("Shader error ", cglShader._name, infoLog, this);

        htmlWarning = infoLog + "<br/>" + htmlWarning + "<br/><br/>";
        htmlWarning += "</code></pre>";

        if (this._fromUserInteraction)
        {
            // console.log("todo show modal?");
            // cgl.patch.emitEvent("criticalError", { "title": "Shader error " + cglShader._name, "text": htmlWarning, "exception": { "message": infoLog } });
        }

        cglShader.setSource(Shader.getDefaultVertexShader(), Shader.getErrorFragmentShader());
    }
    else
    {
        // console.log(name+' shader compiled...');
    }
    // cgl.printError("shader create2");
    return shader;
};













;// CONCATENATED MODULE: ./src/core/cgl/cgl_profiledata.js
class ProfileData
{
    constructor(cgl)
    {
        this._cgl = cgl;
        this._lastTime = 0;
        this.pause = false;
        this.profileUniformCount = 0;
        this.profileShaderBinds = 0;
        this.profileUniformCount = 0;
        this.profileShaderCompiles = 0;
        this.profileVideosPlaying = 0;
        this.profileMVPMatrixCount = 0;
        this.profileEffectBuffercreate = 0;
        this.profileShaderGetUniform = 0;
        this.profileFrameBuffercreate = 0;
        this.profileMeshSetGeom = 0;
        this.profileTextureNew = 0;
        this.profileGenMipMap = 0;
        this.profileOnAnimFrameOps = 0;

        this.profileFencedPixelRead = 0;
        this.profileMainloopMs = 0;
        this.profileMeshDraw = 0;
        this.profileTextureEffect = 0;
        this.profileTexPreviews = 0;
        this.shaderCompileTime = 0;
        this.profileMeshNumElements = 0;
        this.profileMeshAttributes = 0;
        this.profileSingleMeshAttribute = [];
        this.heavyEvents = [];

        this.doProfileGlQuery = false;
        this.glQueryData = {};
    }

    clear()
    {
        this.profileSingleMeshAttribute = {};
        this.profileMeshAttributes = 0;
        this.profileUniformCount = 0;
        this.profileShaderGetUniform = 0;
        this.profileShaderCompiles = 0;
        this.profileShaderBinds = 0;
        this.profileTextureResize = 0;
        this.profileFrameBuffercreate = 0;
        this.profileEffectBuffercreate = 0;
        this.profileTextureDelete = 0;
        this.profileMeshSetGeom = 0;
        this.profileVideosPlaying = 0;
        this.profileMVPMatrixCount = 0;
        this.profileNonTypedAttrib = 0;
        this.profileNonTypedAttribNames = "";
        this.profileTextureNew = 0;
        this.profileGenMipMap = 0;
        this.profileFramebuffer = 0;
        this.profileMeshDraw = 0;
        this.profileTextureEffect = 0;
        this.profileTexPreviews = 0;
        this.profileMeshNumElements = 0;
        this.profileFencedPixelRead = 0;
    }

    clearGlQuery()
    {
        for (let i in this.glQueryData)
        {
            if (!this.glQueryData[i].lastClear || performance.now() - this.glQueryData[i].lastClear > 1000)
            {
                this.glQueryData[i].time = this.glQueryData[i]._times / this.glQueryData[i]._numcount;
                this.glQueryData[i].num = this.glQueryData[i]._numcount;

                this.glQueryData[i]._times = 0;
                this.glQueryData[i]._numcount = 0;
                this.glQueryData[i].lastClear = performance.now();
            }
        }
    }

    addHeavyEvent(event, name, info)
    {
        const e = { "event": event, "name": name, "info": info, "date": performance.now() };
        this.heavyEvents.push(e);
        this._cgl.emitEvent("heavyEvent", e);
    }
}




;// CONCATENATED MODULE: ../shared/client/src/helper.js
/**
 * Shared helper methods for cables uis
 */
class Helper
{
    constructor()
    {
        this._simpleIdCounter = 0;
    }


    /**
     * generate a random v4 uuid
     *
     * @return {string}
     */
    uuid()
    {
        let d = new Date().getTime();
        return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) =>
        {
            const r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c === "x" ? r : (r & 0x3) | 0x8).toString(16);
        });
    }

    /**
     * checks value for !isNan and isFinite
     *
     * @param n
     * @return {boolean}
     */
    isNumeric(n)
    {
        return !isNaN(parseFloat(n)) && isFinite(n);
    }

    /**
     * generate a simple ID using an internal counter
     *
     * @return {Number} new id
     * @static
     */
    simpleId()
    {
        this._simpleIdCounter++;
        return this._simpleIdCounter;
    }

    deletePropertyByPath(obj, path)
    {
        if (!obj || !path)
        {
            return;
        }

        if (typeof path === "string")
        {
            path = path.split(".");
        }

        for (let i = 0; i < path.length - 1; i++)
        {
            obj = obj[path[i]];

            if (typeof obj === "undefined")
            {
                return;
            }
        }

        delete obj[path.pop()];
    }
}
/* harmony default export */ const helper = (new Helper());

;// CONCATENATED MODULE: ../shared/client/src/eventtarget.js



/**
 * add eventlistener functionality to classes
 */
class Events
{
    constructor()
    {
        this._log = new Logger("eventtarget");
        this._eventCallbacks = {};
        this._logName = "";
        this._logEvents = false;
        this._listeners = {};

        this.on = this.addEventListener;
        this.off = this.removeEventListener;
    }

    /**
     * add event listener
     * @param which event name
     * @param cb callback
     * @param {string} idPrefix prefix for id, default empty
     * @return {string} event id
     */
    addEventListener(which, cb, idPrefix = "")
    {
        const event =
            {
                "id": (idPrefix || "") + helper.simpleId(),
                "name": which,
                "cb": cb,
            };
        if (!this._eventCallbacks[which]) this._eventCallbacks[which] = [event];
        else this._eventCallbacks[which].push(event);

        this._listeners[event.id] = event;

        return event.id;
    }

    /**
     * check event listener registration
     * @param id event id
     * @param cb callback - deprecated
     * @return {boolean}
     */
    hasEventListener(id, cb = null)
    {
        if (id && !cb)
        {
            // check by id
            return !!this._listeners[id];
        }
        else
        {
            this._log.warn("old eventtarget function haseventlistener!");
            if (id && cb)
            {
                if (this._eventCallbacks[id])
                {
                    const idx = this._eventCallbacks[id].indexOf(cb);
                    return idx !== -1;
                }
            }
        }
    }

    /**
     * check event listener by name
     * @param eventName event name
     * @return {boolean}
     */
    hasListenerForEventName(eventName)
    {
        return this._eventCallbacks[eventName] && this._eventCallbacks[eventName].length > 0;
    }

    /**
     * rempve event listener registration
     * @param id event id
     * @param cb callback - deprecated
     * @return
     */
    removeEventListener(id, cb = null)
    {
        if (id === null || id === undefined) return;

        if (!cb) // new style, remove by id, not by name/callback
        {
            const event = this._listeners[id];
            if (!event)
            {
                this._log.log("could not find event...", id, this);
                return;
            }

            let found = true;
            while (found)
            {
                found = false;
                let index = -1;
                for (let i = 0; i < this._eventCallbacks[event.name].length; i++)
                {
                    if (this._eventCallbacks[event.name][i].id.indexOf(id) === 0) // this._eventCallbacks[event.name][i].id == which ||
                    {
                        found = true;
                        index = i;
                    }
                }

                if (index !== -1)
                {
                    this._eventCallbacks[event.name].splice(index, 1);
                    delete this._listeners[id];
                }
            }

            return;
        }

        this._log.info("[eventtaget] ", "old function signature: removeEventListener! use listener id");
        this._log.log((new Error()).stack);

        let index = null;
        for (let i = 0; i < this._eventCallbacks[id].length; i++)
            if (this._eventCallbacks[id][i].cb === cb)
                index = i;

        if (index !== null)
        {
            delete this._eventCallbacks[index];
        }
        else this._log.warn("removeEventListener not found " + id);
    }

    /**
     * enable/disable logging of events for the class
     *
     * @param {boolean} enabled
     * @param {string} logName
     */
    logEvents(enabled, logName)
    {
        this._logEvents = enabled;
        this._logName = logName;
    }

    /**
     * emit event
     *
     * @param {string} which event name
     * @param {*} param1
     * @param {*} param2
     * @param {*} param3
     * @param {*} param4
     * @param {*} param5
     * @param {*} param6
     */
    emitEvent(which, param1 = null, param2 = null, param3 = null, param4 = null, param5 = null, param6 = null)
    {
        if (this._logEvents) this._log.log("[event] ", this._logName, which, this._eventCallbacks);

        if (this._eventCallbacks[which])
        {
            for (let i = 0; i < this._eventCallbacks[which].length; i++)
            {
                if (this._eventCallbacks[which][i])
                {
                    this._eventCallbacks[which][i].cb(param1, param2, param3, param4, param5, param6);
                }
            }
        }
        else
        {
            if (this._logEvents) this._log.log("[event] has no event callback", which, this._eventCallbacks);
        }
    }
}


;// CONCATENATED MODULE: ./src/core/cg/cg_canvas.js
class CgCanvas
{
    constructor(options)
    {
        if (!options)
        {
            console.error("CgCanvas no options");
        }
        else
        {
            this._canvasEle = options.canvasEle;
        }

        if (!options.cg)console.error("CgCanvas options has no cg");
        if (!options.canvasEle)console.error("CgCanvas options has no canvasEle");

        this._cg = options.cg;
        this.pixelDensity = 1;
        this.canvasWidth = this.canvasEle.clientWidth;
        this.canvasHeight = this.canvasEle.clientHeight;

        this._oldWidthRp = -1;
        this._oldHeightRp = -1;

        this.setSize(this.canvasWidth, this.canvasHeight);
    }

    get canvasEle() { return this._canvasEle; }


    setSize(w, h, ignorestyle)
    {
        if (this._oldWidthRp != w * this.pixelDensity || this._oldHeightRp != h * this.pixelDensity)
        {
            this._oldWidthRp = this.canvasEle.width = w * this.pixelDensity;
            this._oldHeightRp = this.canvasEle.height = h * this.pixelDensity;

            if (!ignorestyle)
            {
                this.canvasEle.style.width = w + "px";
                this.canvasEle.style.height = h + "px";
            }

            this.updateSize();

            this._cg.emitEvent("resize");
        }
    }

    updateSize()
    {
        this.canvasEle.width = this.canvasWidth = this.canvasEle.clientWidth * this.pixelDensity;
        this.canvasEle.height = this.canvasHeight = this.canvasEle.clientHeight * this.pixelDensity;
    }

    dispose()
    {
        this._canvasEle.remove();
        this._canvasEle = null;
    }
}



;// CONCATENATED MODULE: ./src/core/cg/cg_matrixstack.js

const MatrixStack = function ()
{
    this._arr = [mat4.create()];
    this._index = 0;
    this.stateCounter = 0;
};

MatrixStack.prototype.push = function (m)
{
    this._index++;
    this.stateCounter++;

    if (this._index == this._arr.length)
    {
        const copy = mat4.create();
        this._arr.push(copy);
    }

    mat4.copy(this._arr[this._index], m || this._arr[this._index - 1]);

    return this._arr[this._index];
};

MatrixStack.prototype.pop = function ()
{
    this.stateCounter++;

    this._index--;
    if (this._index < 0) this._index = 0;

    return this._arr[this._index];
};

MatrixStack.prototype.length = function ()
{
    return this._index;
};



;// CONCATENATED MODULE: ./src/core/cg/cg_state.js




class CGState extends Events
{
    constructor(_patch)
    {
        super();
        this.tempData = this.frameStore = this.frameStore || {};
        // this.canvas = null;

        this.fpsCounter = new CABLES.CG.FpsCounter();
        this._identView = vec3.create();
        this._ident = vec3.create();
        vec3.set(this._identView, 0, 0, -2);
        vec3.set(this._ident, 0, 0, 0);

        this.patch = _patch;
        this.autoReSize = true;

        this.DEPTH_COMPARE_FUNC_NEVER = 0;
        this.DEPTH_COMPARE_FUNC_LESS = 1;
        this.DEPTH_COMPARE_FUNC_EQUAL = 2;
        this.DEPTH_COMPARE_FUNC_LESSEQUAL = 3;
        this.DEPTH_COMPARE_FUNC_GREATER = 4;
        this.DEPTH_COMPARE_FUNC_NOTEQUAL = 5;
        this.DEPTH_COMPARE_FUNC_GREATEREQUAL = 6;
        this.DEPTH_COMPARE_FUNC_ALWAYS = 7;


        /**
         * Current projection matrix
         * @memberof Context
         * @instance
         * @type {mat4}
         */
        this.pMatrix = mat4.create();

        /**
         * Current model matrix
         * @memberof Context
         * @instance
         * @type {mat4}
         */
        this.mMatrix = mat4.create();

        /**
         * Current view matrix
         * @memberof Context
         * @instance
         * @type {mat4}
         */
        this.vMatrix = mat4.create();
        this._textureslots = [];

        this._pMatrixStack = new MatrixStack();
        this._mMatrixStack = new MatrixStack();
        this._vMatrixStack = new MatrixStack();

        this.canvasScale = 1;

        mat4.identity(this.mMatrix);
        mat4.identity(this.vMatrix);


        window.matchMedia("screen and (min-resolution: 2dppx)")
            .addEventListener("change", (e) =>
            {
                this.emitEvent("resize");
            });
    }

    get canvasWidth()
    {
        return this.cgCanvas.canvasWidth;
    }

    get canvasHeight()
    {
        return this.cgCanvas.canvasHeight;
    }

    set pixelDensity(p)
    {
        if (this.cgCanvas.pixelDensity != p)
        {
            this.cgCanvas.pixelDensity = p;
            this.cgCanvas.updateSize();
            this.emitEvent("resize");
        }
    }

    get pixelDensity()
    {
        return this.cgCanvas.pixelDensity;
    }


    getGApiName()
    {
        return ["WebGL", "WebGPU"][this.gApi];
    }

    get canvas()
    {
        return this.cgCanvas.canvasEle;
    }



    setCanvas(canvEle)
    {
        if (this.cgCanvas && canvEle == this.cgCanvas.canvasEle) return;
        if (typeof canvEle === "string") canvEle = document.getElementById(canvEle);

        this.cgCanvas = new CgCanvas({ "canvasEle": canvEle, "cg": this });

        canvEle.parentElement.classList.add("cablesContainer");
        if (this._setCanvas) this._setCanvas(canvEle);

        this.updateSize();
    }

    updateSize()
    {
        this.cgCanvas.updateSize();
    }

    setSize(w, h, ignorestyle)
    {
        this.cgCanvas.setSize(w, h, ignorestyle);
    }

    _resizeToWindowSize()
    {
        if (this.autoReSize)
        {
            this.setSize(window.innerWidth, window.innerHeight);
            this.updateSize();
        }
    }

    _resizeToParentSize()
    {
        if (this.autoReSize)
        {
            const p = this.canvas.parentElement;
            if (!p)
            {
                this._log.error("cables: can not resize to container element");
                return;
            }

            this.setSize(p.clientWidth, p.clientHeight);
            this.updateSize();
        }
    }

    setAutoResize(parent)
    {
        window.removeEventListener("resize", this._resizeToWindowSize.bind(this));
        window.removeEventListener("resize", this._resizeToParentSize.bind(this));

        if (parent == "window")
        {
            window.addEventListener("resize", this._resizeToWindowSize.bind(this));
            window.addEventListener("orientationchange", this._resizeToWindowSize.bind(this));
            this._resizeToWindowSize();
        }
        if (parent == "parent")
        {
            window.addEventListener("resize", this._resizeToParentSize.bind(this));
            this._resizeToParentSize();
        }
    }

    /**
     * push a matrix to the projection matrix stack
     * @function pushPMatrix
     * @memberof Context
     * @instance
     */
    pushPMatrix()
    {
        this.pMatrix = this._pMatrixStack.push(this.pMatrix);
    }

    /**
      * pop projection matrix stack
      * @function popPMatrix
      * @memberof Context
      * @instance
      * @returns {mat4} current projectionmatrix
      */
    popPMatrix()
    {
        this.pMatrix = this._pMatrixStack.pop();
        return this.pMatrix;
    }

    getProjectionMatrixStateCount()
    {
        return this._pMatrixStack.stateCounter;
    }

    /**
      * push a matrix to the model matrix stack
      * @function pushModelMatrix
      * @memberof Context
      * @instance
      * @example
      * // see source code of translate op:
      * cgl.pushModelMatrix();
      * mat4.translate(cgl.mMatrix,cgl.mMatrix, vec);
      * trigger.trigger();
      * cgl.popModelMatrix();
      */
    pushModelMatrix()
    {
        this.mMatrix = this._mMatrixStack.push(this.mMatrix);
    }

    /**
      * pop model matrix stack
      * @function popModelMatrix
      * @memberof Context
      * @instance
      * @returns {mat4} current modelmatrix
      */
    popModelMatrix()
    {
        // todo: DEPRECATE
        // if (this._mMatrixStack.length === 0) throw "Invalid modelview popMatrix!";
        this.mMatrix = this._mMatrixStack.pop();
        return this.mMatrix;
    }

    /**
      * get model matrix
      * @function modelMatrix
      * @memberof Context
      * @instance
      * @returns {mat4} current modelmatrix
      */
    modelMatrix()
    {
        return this.mMatrix;
    }


    /**
     * push a matrix to the view matrix stack
     * @function pushviewMatrix
     * @memberof Context
     * @instance
     */
    pushViewMatrix()
    {
        this.vMatrix = this._vMatrixStack.push(this.vMatrix);
    }

    /**
      * pop view matrix stack
      * @function popViewMatrix
      * @memberof Context
      * @instance
      * @returns {mat4} current viewmatrix
      * @function
      */
    popViewMatrix()
    {
        this.vMatrix = this._vMatrixStack.pop();
    }

    getViewMatrixStateCount()
    {
        return this._vMatrixStack.stateCounter;
    }

    _startMatrixStacks(identTranslate, identTranslateView)
    {
        identTranslate = identTranslate || this._ident;
        identTranslateView = identTranslateView || this._identView;

        mat4.perspective(this.pMatrix, 45, this.canvasWidth / this.canvasHeight, 0.1, 1000.0);

        mat4.identity(this.mMatrix);
        mat4.identity(this.vMatrix);
        mat4.translate(this.mMatrix, this.mMatrix, identTranslate);
        mat4.translate(this.vMatrix, this.vMatrix, identTranslateView);

        this.pushPMatrix();
        this.pushModelMatrix();
        this.pushViewMatrix();
    }

    _endMatrixStacks()
    {
        this.popViewMatrix();
        this.popModelMatrix();
        this.popPMatrix();
    }

    dispose()
    {
        this.aborted = true;
        if (this.cgCanvas) this.cgCanvas.dispose();
        if (this._dispose) this._dispose();
    }

    shouldDrawHelpers()
    {
        return false;
    }
}





;// CONCATENATED MODULE: ./src/core/cg/sg_fpscounter.js


class FpsCounter extends Events
{
    constructor()
    {
        super();
        this._timeStartFrame = 0;
        this._timeStartSecond = 0;
        this._fpsCounter = 0;
        this._msCounter = 0;
        this._frameCount = 0;

        this.stats = { "ms": 0, "fps": 0 };
    }

    get frameCount()
    {
        return this._frameCount;
    }

    startFrame()
    {
        this._timeStartFrame = CABLES.now();
    }

    endFrame()
    {
        this._frameCount++;
        this._fpsCounter++;

        const timeFrame = CABLES.now() - this._timeStartFrame;
        this._msCounter += timeFrame;

        if (CABLES.now() - this._timeStartSecond > 1000)
        {
            this.endSecond();
        }
    }

    endSecond()
    {
        this.stats.fps = this._fpsCounter;
        this.stats.ms = Math.round(this._msCounter / this._fpsCounter * 100) / 100;

        this.emitEvent("performance", this.stats);

        // reset
        this._fpsCounter = 0;
        this._msCounter = 0;
        this._timeStartSecond = CABLES.now();
    }
}

;// CONCATENATED MODULE: ./src/core/cg/cg_constants.js





const CG = {

    "GAPI_WEBGL": 0,
    "GAPI_WEBGPU": 1,

    "DEPTH_COMPARE_NEVER": 0,
    "DEPTH_COMPARE_LESS": 1,
    "DEPTH_COMPARE_EQUAL": 2,
    "DEPTH_COMPARE_LESSEQUAL": 3,
    "DEPTH_COMPARE_GREATER": 4,
    "DEPTH_COMPARE_NOTEQUAL": 5,
    "DEPTH_COMPARE_GREATEREQUAL": 6,
    "DEPTH_COMPARE_ALWAYS": 7,

    "CULL_NONE": 0,
    "CULL_BACK": 1,
    "CULL_FRONT": 2,
    "CULL_BOTH": 3,


    "Geometry": Geometry,
    "BoundingBox": BoundingBox,
    "FpsCounter": FpsCounter,

    "CgCanvas": CgCanvas
};




;// CONCATENATED MODULE: ./src/core/cgl/cgl_state.js








/**
 * cables gl context/state manager
 * @class
 * @namespace external:CGL
 * @hideconstructor
 */
// const Context(_patch)
class Context extends CGState
{
    constructor(_patch)
    {
        super(_patch);

        this.gApi = CG.GAPI_WEBGL;
        this.aborted = false;

        this.pushMvMatrix = this.pushModelMatrix; // deprecated and wrong... still used??
        this.popMvMatrix = this.popmMatrix = this.popModelMatrix;// deprecated and wrong... still used??

        this.profileData = new ProfileData(this);
        this._log = new Logger("cgl_context", { "onError": _patch.config.onError });
        this._viewPort = [0, 0, 0, 0];
        this.glVersion = 0;
        this.glUseHalfFloatTex = false;
        this.clearCanvasTransparent = true;
        this.clearCanvasDepth = true;
        this.debugOneFrame = false;
        this.checkGlErrors = false; // true is slow // false should be default...
        this.maxTextureUnits = 0;
        this.maxVaryingVectors = 0;
        this.currentProgram = null;
        this._hadStackError = false;
        this.glSlowRenderer = false;
        this._isSafariCrap = false;

        this.temporaryTexture = null;
        this._onetimeCallbacks = [];
        this.gl = null;

        this._cursor = "auto";
        this._currentCursor = "";

        this._viewPortStack = [];
        this._glFrameBufferStack = [];
        this._frameBufferStack = [];
        this._shaderStack = [];
        this._stackDepthTest = [];
        this.mainloopOp = null;

        this._simpleShader = new Shader(this, "simpleshader");
        this._simpleShader.setModules(["MODULE_VERTEX_POSITION", "MODULE_COLOR", "MODULE_BEGIN_FRAG", "MODULE_VERTEX_MODELVIEW"]);
        this._simpleShader.setSource(Shader.getDefaultVertexShader(), Shader.getDefaultFragmentShader());

        this._currentShader = this._simpleShader;


        this._oldCanvasWidth = -1;
        this._oldCanvasHeight = -1;
        this._enabledExtensions = {};
    }

    // set pixelDensity(p)
    // {
    //     this._pixelDensity = p;
    // }

    // get pixelDensity()
    // {
    //     return this._pixelDensity;
    // }



    get viewPort()
    {
        if (this._viewPortStack.length > 3)
        {
            const l = this._viewPortStack.length;

            return [
                this._viewPortStack[l - 4],
                this._viewPortStack[l - 3],
                this._viewPortStack[l - 2],
                this._viewPortStack[l - 1]
            ];
        }
        else
        {
            // workaround pre viewport stack times / or+and initial value...

            return this._viewPort;
        }
    }



    get mvMatrix() // deprecate
    {
        return this.mMatrix;
    }

    set mvMatrix(m) // deprecate
    {
        this.mMatrix = m;
    }

    _setCanvas(canv)
    {
        if (!canv) this._log.stack("_setCanvas undef");

        if (!this.patch.config.canvas) this.patch.config.canvas = {};
        if (!this.patch.config.canvas.hasOwnProperty("preserveDrawingBuffer")) this.patch.config.canvas.preserveDrawingBuffer = false;
        if (!this.patch.config.canvas.hasOwnProperty("premultipliedAlpha")) this.patch.config.canvas.premultipliedAlpha = false;
        if (!this.patch.config.canvas.hasOwnProperty("alpha")) this.patch.config.canvas.alpha = false;

        this.patch.config.canvas.stencil = true;

        if (this.patch.config.hasOwnProperty("clearCanvasColor")) this.clearCanvasTransparent = this.patch.config.clearCanvasColor;
        if (this.patch.config.hasOwnProperty("clearCanvasDepth")) this.clearCanvasDepth = this.patch.config.clearCanvasDepth;

        // safari stuff..........
        if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent) && (navigator.userAgent.match(/iPhone/i)))
        {
            this._isSafariCrap = true;
            this.glUseHalfFloatTex = true;
        }

        if (!this.patch.config.canvas.forceWebGl1) this.gl = canv.getContext("webgl2", this.patch.config.canvas);


        if (!this.gl || this.gl.isContextLost())
        {
            this.aborted = true;
            this._log.error("NO_WEBGL", "sorry, could not initialize WebGL. Please check if your Browser supports WebGL or try to restart your browser.");
            return;
        }

        if (this.gl.getParameter(this.gl.VERSION) != "WebGL 1.0")
        {
            this.glVersion = 2;
        }
        else
        {
            this.gl = canv.getContext("webgl", this.patch.config.canvas) || canv.getContext("experimental-webgl", this.patch.config.canvas);
            this.glVersion = 1;

            // safari
            // if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent) && (navigator.userAgent.match(/iPhone/i)))
            // {
            //     this.glUseHalfFloatTex = true;
            // }

            // ios
            if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream)
            {
                if (!this.patch.config.canvas.hasOwnProperty("powerPreference")) this.patch.config.canvas.powerPreference = "high-performance";
            }

            this.enableExtension("OES_standard_derivatives");
            // this.enableExtension("GL_OES_standard_derivatives");
            const instancingExt = this.enableExtension("ANGLE_instanced_arrays") || this.gl;
            if (instancingExt.vertexAttribDivisorANGLE)
            {
                this.gl.vertexAttribDivisor = instancingExt.vertexAttribDivisorANGLE.bind(instancingExt);
                this.gl.drawElementsInstanced = instancingExt.drawElementsInstancedANGLE.bind(instancingExt);
            }
        }

        const dbgRenderInfo = this.enableExtension("WEBGL_debug_renderer_info");
        if (dbgRenderInfo)
        {
            this.glRenderer = this.gl.getParameter(dbgRenderInfo.UNMASKED_RENDERER_WEBGL);
            if (this.glRenderer === "Google SwiftShader") this.glSlowRenderer = true;
        }

        this.canvas.addEventListener("webglcontextlost", (event) =>
        {
            if (this.aborted) return this._log.warn("[cgl_state] aborted context lost... can be ignored...");
            this._log.error("canvas lost...", event);
            this.emitEvent("webglcontextlost");
            this.aborted = true;
        });


        this.maxAnisotropic = 0;
        if (this.enableExtension("EXT_texture_filter_anisotropic"))
            this.maxAnisotropic = this.gl.getParameter(this.enableExtension("EXT_texture_filter_anisotropic").MAX_TEXTURE_MAX_ANISOTROPY_EXT);


        this.maxVaryingVectors = this.gl.getParameter(this.gl.MAX_VARYING_VECTORS);
        this.maxTextureUnits = this.gl.getParameter(this.gl.MAX_TEXTURE_IMAGE_UNITS);
        this.maxTexSize = this.gl.getParameter(this.gl.MAX_TEXTURE_SIZE);
        this.maxUniformsFrag = this.gl.getParameter(this.gl.MAX_FRAGMENT_UNIFORM_VECTORS);
        this.maxUniformsVert = this.gl.getParameter(this.gl.MAX_VERTEX_UNIFORM_VECTORS);
        this.maxSamples = 0;
        if (this.gl.MAX_SAMPLES) this.maxSamples = this.gl.getParameter(this.gl.MAX_SAMPLES);

        if (this.glVersion == 1)
        {
            this.enableExtension("OES_standard_derivatives");
            const instancingExt = this.enableExtension("ANGLE_instanced_arrays") || this.gl;

            if (instancingExt.vertexAttribDivisorANGLE)
            {
                this.gl.vertexAttribDivisor = instancingExt.vertexAttribDivisorANGLE.bind(instancingExt);
                this.gl.drawElementsInstanced = instancingExt.drawElementsInstancedANGLE.bind(instancingExt);
            }
        }

        this.DEPTH_FUNCS = [
            this.gl.NEVER,
            this.gl.ALWAYS,
            this.gl.LESS,
            this.gl.LEQUAL,
            this.gl.GREATER,
            this.gl.GEQUAL,
            this.gl.EQUAL,
            this.gl.NOTEQUAL
        ];
        this.CULL_MODES = [
            null,
            this.gl.BACK,
            this.gl.FRONT,
            this.gl.FRONT_AND_BACK
        ];
    }

    getInfo()
    {
        return {
            "glVersion": this.glVersion,
            "glRenderer": this.glRenderer,
            "glUseHalfFloatTex": this.glUseHalfFloatTex,
            "maxVaryingVectors": this.maxVaryingVectors,
            "maxTextureUnits": this.maxTextureUnits,
            "maxTexSize": this.maxTexSize,
            "maxUniformsFrag": this.maxUniformsFrag,
            "maxUniformsVert": this.maxUniformsVert,
            "maxSamples": this.maxSamples
        };
    }





    /**
     * @function popViewPort
     * @memberof Context
     * @instance
     * @description pop viewPort stack
     */


    popViewPort()
    {
        this._viewPortStack.pop();
        this._viewPortStack.pop();
        this._viewPortStack.pop();
        this._viewPortStack.pop();

        if (this._viewPortStack.length == 0)
        {
            this.setViewPort(0, 0, this.canvasWidth, this.canvasHeight);
            // this.gl.viewport(this._viewPort[0], this._viewPort[1], this._viewPort[2], this._viewPort[3]);
            // this.setViewPort(this._viewPort[0], this._viewPort[1], this._viewPort[2], this._viewPort[3]);
        }
        else
        {
            // this.viewPort = [this._viewPortStack[this._viewPort.length - 4], this._viewPortStack[this._viewPort.length - 3], this._viewPortStack[this._viewPort.length - 2], this._viewPortStack[this._viewPort.length - 1]];
            // this.gl.viewport(this._viewPortStack[this._viewPort.length - 4], this._viewPortStack[this._viewPort.length - 3], this._viewPortStack[this._viewPort.length - 2], this._viewPortStack[this._viewPort.length - 1]);
            this.setViewPort(this._viewPortStack[this._viewPort.length - 4], this._viewPortStack[this._viewPort.length - 3], this._viewPortStack[this._viewPort.length - 2], this._viewPortStack[this._viewPort.length - 1]);
        }
    }

    /**
     * @function pushViewPort
     * @memberof Context
     * @instance
     * @description push a new viewport onto stack
     * @param {Number} x
     * @param {Number} y
     * @param {Number} w
     * @param {Number} h
     */

    pushViewPort(x, y, w, h)
    {
        this._viewPortStack.push(x, y, w, h);
        this.setViewPort(x, y, w, h);
    }


    // old
    getViewPort()
    {
        return this._viewPort;
    }

    // old
    resetViewPort()
    {
        this.gl.viewport(this._viewPort[0], this._viewPort[1], this._viewPort[2], this._viewPort[3]);
    }

    // old
    setViewPort(x, y, w, h)
    {
        this._viewPort[0] = Math.round(x);
        this._viewPort[1] = Math.round(y);
        this._viewPort[2] = Math.round(w);
        this._viewPort[3] = Math.round(h);
        this.gl.viewport(this._viewPort[0], this._viewPort[1], this._viewPort[2], this._viewPort[3]);
    }


    screenShot(cb, doScreenshotClearAlpha, mimeType, quality)
    {
        if (doScreenshotClearAlpha)
        {
            this.gl.clearColor(1, 1, 1, 1);
            this.gl.colorMask(false, false, false, true);
            this.gl.clear(this.gl.COLOR_BUFFER_BIT);
            this.gl.colorMask(true, true, true, true);
        }

        if (this.canvas && this.canvas.toBlob)
        {
            this.canvas.toBlob((blob) =>
            {
                if (cb) cb(blob);
                else this._log.log("no screenshot callback...");
            }, mimeType, quality);
        }
    }

    endFrame()
    {
        if (this.patch.isEditorMode()) CABLES.GL_MARKER.drawMarkerLayer(this);

        this.setPreviousShader();

        if (this._vMatrixStack.length() > 0) this.logStackError("view matrix stack length !=0 at end of rendering...");
        if (this._mMatrixStack.length() > 0) this.logStackError("mvmatrix stack length !=0 at end of rendering...");
        if (this._pMatrixStack.length() > 0) this.logStackError("pmatrix stack length !=0 at end of rendering...");
        if (this._glFrameBufferStack.length > 0) this.logStackError("glFrameBuffer stack length !=0 at end of rendering...");
        if (this._stackDepthTest.length > 0) this.logStackError("depthtest stack length !=0 at end of rendering...");
        if (this._stackDepthWrite.length > 0) this.logStackError("depthwrite stack length !=0 at end of rendering...");
        if (this._stackDepthFunc.length > 0) this.logStackError("depthfunc stack length !=0 at end of rendering...");
        if (this._stackBlend.length > 0) this.logStackError("blend stack length !=0 at end of rendering...");
        if (this._stackBlendMode.length > 0) this.logStackError("blendMode stack length !=0 at end of rendering...");
        if (this._shaderStack.length > 0) this.logStackError("this._shaderStack length !=0 at end of rendering...");
        if (this._stackCullFace.length > 0) this.logStackError("this._stackCullFace length !=0 at end of rendering...");
        if (this._stackCullFaceFacing.length > 0) this.logStackError("this._stackCullFaceFacing length !=0 at end of rendering...");
        if (this._viewPortStack.length > 0) this.logStackError("viewport stack length !=0 at end of rendering...");

        this._frameStarted = false;

        if (this._oldCanvasWidth != this.canvasWidth || this._oldCanvasHeight != this.canvasHeight)
        {
            this._oldCanvasWidth = this.canvasWidth;
            this._oldCanvasHeight = this.canvasHeight;
            this.emitEvent("resize");
        }

        if (this._cursor != this._currentCursor)
        {
            this._currentCursor = this.canvas.style.cursor = this._cursor;
        }

        this.emitEvent("endframe");

        this.fpsCounter.endFrame();
    }

    logStackError(str)
    {
        if (!this._hadStackError)
        {
            this._hadStackError = true;
            this._log.warn("[" + this.canvas.id + "]: ", str);
        }
    }

    // shader stack
    getShader()
    {
        if (this._currentShader) if (!this.tempData || ((this.tempData.renderOffscreen === true) == this._currentShader.offScreenPass) === true) return this._currentShader;

        for (let i = this._shaderStack.length - 1; i >= 0; i--) if (this._shaderStack[i]) if (this.tempData.renderOffscreen == this._shaderStack[i].offScreenPass) return this._shaderStack[i];
    }

    getDefaultShader()
    {
        return this._simpleShader;
    }

    /**
     * push a shader to the shader stack
     * @function pushShader
     * @memberof Context
     * @instance
     * @param {Object} shader
     * @function
     */

    pushShader(shader)
    {
        if (this.tempData.forceShaderMods)
        {
            for (let i = 0; i < this.tempData.forceShaderMods.length; i++)
            {
                // if (!currentShader.forcedMod && currentShader != this.tempData.forceShaderMods[i])
                // {
                //     currentShader.forcedMod = this.tempData.forceShaderMods[i];
                shader = this.tempData.forceShaderMods[i].bind(shader, false);
                // }
                // return currentShader;
                // if (this.tempData.forceShaderMods[i].currentShader() && shader != this.tempData.forceShaderMods[i].currentShader().shader)
            }
        }

        this._shaderStack.push(shader);
        this._currentShader = shader;
    }


    /**
     * pop current used shader from shader stack
     * @function popShader
     * @memberof Context
     * @instance
     * @function
     */
    setPreviousShader()
    {
        if (this.tempData.forceShaderMods)
        {
            for (let i = 0; i < this.tempData.forceShaderMods.length; i++)
            {
                // const a =
                this.tempData.forceShaderMods[i].unbind(false);
                // if (a) return;
                // this.popShader();
            }
        }

        if (this._shaderStack.length === 0) throw new Error("Invalid shader stack pop!");
        this._shaderStack.pop();
        this._currentShader = this._shaderStack[this._shaderStack.length - 1];
    }

    /**
     * push a framebuffer to the framebuffer stack
     * @function pushGlFrameBuffer
     * @memberof Context
     * @instance
     * @param {Object} fb framebuffer
     * @function
     */
    pushGlFrameBuffer(fb)
    {
        this._glFrameBufferStack.push(fb);
    }

    /**
     * pop framebuffer stack
     * @function popGlFrameBuffer
     * @memberof Context
     * @instance
     * @returns {Object} current framebuffer or null
     */
    popGlFrameBuffer()
    {
        if (this._glFrameBufferStack.length == 0) return null;
        this._glFrameBufferStack.pop();
        return this._glFrameBufferStack[this._glFrameBufferStack.length - 1];
    }

    /**
     * get current framebuffer
     * @function getCurrentFrameBuffer
     * @memberof Context
     * @instance
     * @returns {Object} current framebuffer or null
     */
    getCurrentGlFrameBuffer()
    {
        if (this._glFrameBufferStack.length === 0) return null;
        return this._glFrameBufferStack[this._glFrameBufferStack.length - 1];
    }

    /**
     * push a framebuffer to the framebuffer stack
     * @function pushGlFrameBuffer
     * @memberof Context
     * @instance
     * @param {Framebuffer} fb framebuffer
     */
    pushFrameBuffer(fb)
    {
        this._frameBufferStack.push(fb);
    }

    /**
     * pop framebuffer stack
     * @function popFrameBuffer
     * @memberof Context
     * @instance
     * @returns {Framebuffer} current framebuffer or null
     */
    popFrameBuffer()
    {
        if (this._frameBufferStack.length == 0) return null;
        this._frameBufferStack.pop();
        return this._frameBufferStack[this._frameBufferStack.length - 1];
    }

    /**
     * get current framebuffer
     * @function getCurrentFrameBuffer
     * @memberof Context
     * @instance
     * @returns {Framebuffer} current framebuffer or null
     */
    getCurrentFrameBuffer()
    {
        if (this._frameBufferStack.length === 0) return null;
        return this._frameBufferStack[this._frameBufferStack.length - 1];
    }


    renderStart(cgl, identTranslate, identTranslateView)
    {
        this.fpsCounter.startFrame();
        this.pushDepthTest(true);
        this.pushDepthWrite(true);
        this.pushDepthFunc(cgl.gl.LEQUAL);
        this.pushCullFaceFacing(cgl.gl.BACK);
        this.pushCullFace(false);

        // if (this.clearCanvasTransparent)
        // {
        //     cgl.gl.clearColor(0, 0, 0, 0);
        //     cgl.gl.clear(cgl.gl.COLOR_BUFFER_BIT);
        // }
        // if (this.clearCanvasDepth) cgl.gl.clear(cgl.gl.DEPTH_BUFFER_BIT);

        cgl.setViewPort(0, 0, cgl.canvasWidth, cgl.canvasHeight);

        this._startMatrixStacks(identTranslate, identTranslateView);

        cgl.pushBlendMode(constants_CONSTANTS.BLEND_MODES.BLEND_NORMAL, false);

        for (let i = 0; i < this._textureslots.length; i++) this._textureslots[i] = null;

        this.pushShader(this._simpleShader);

        this._frameStarted = true;

        if (this._onetimeCallbacks.length > 0)
        {
            for (let i = 0; i < this._onetimeCallbacks.length; i++) this._onetimeCallbacks[i]();
            this._onetimeCallbacks.length = 0;
        }

        for (let i = 0; i < this._textureslots.length; i++)
        {
            this.gl.activeTexture(this.gl.TEXTURE0 + i);
            this.gl.bindTexture(this.gl.TEXTURE_2D, null);
            this._textureslots[i] = null;
        }

        this.emitEvent("beginFrame");
    }

    renderEnd(cgl)
    {
        this._endMatrixStacks();

        this.popDepthTest();
        this.popDepthWrite();
        this.popDepthFunc();
        this.popCullFaceFacing();
        this.popCullFace();
        this.popBlend();
        this.popBlendMode();

        cgl.endFrame();

        this.emitEvent("endFrame");
    }

    getTexture(slot)
    {
        return this._textureslots[slot];
    }

    hasFrameStarted()
    {
        return this._frameStarted;
    }

    /**
     * log warning to console if the rendering of one frame has not been started / handy to check for async problems
     * @function checkFrameStarted
     * @memberof Context
     * @param string
     * @instance
     */
    checkFrameStarted(string)
    {
        if (!this._frameStarted)
        {
            this._log.warn("frame not started " + string);
            this.patch.printTriggerStack();
        }
    }


    setTexture(slot, t, type)
    {
        this.checkFrameStarted("cgl setTexture");

        if (t === null) t = CGL.Texture.getEmptyTexture(this).tex;

        if (this._textureslots[slot] != t)
        {
            this.gl.activeTexture(this.gl.TEXTURE0 + slot);
            this.gl.bindTexture(type || this.gl.TEXTURE_2D, t);
            this._textureslots[slot] = t;
        }


        return true;
    }

    fullScreen()
    {
        if (this.canvas.requestFullscreen) this.canvas.requestFullscreen();
        else if (this.canvas.mozRequestFullScreen) this.canvas.mozRequestFullScreen();
        else if (this.canvas.webkitRequestFullscreen) this.canvas.webkitRequestFullscreen();
        else if (this.canvas.msRequestFullscreen) this.canvas.msRequestFullscreen();
    }


    printError(str)
    {
        if (!this.checkGlErrors) return;
        let found = false;
        let error = this.gl.getError();

        if (error != this.gl.NO_ERROR)
        {
            let errStr = "";
            if (error == this.gl.OUT_OF_MEMORY) errStr = "OUT_OF_MEMORY";
            if (error == this.gl.INVALID_ENUM) errStr = "INVALID_ENUM";
            if (error == this.gl.INVALID_OPERATION) errStr = "INVALID_OPERATION";
            if (error == this.gl.INVALID_FRAMEBUFFER_OPERATION) errStr = "INVALID_FRAMEBUFFER_OPERATION";
            if (error == this.gl.INVALID_VALUE) errStr = "INVALID_VALUE";
            if (error == this.gl.CONTEXT_LOST_WEBGL)
            {
                this.aborted = true;
                errStr = "CONTEXT_LOST_WEBGL";
            }
            if (error == this.gl.NO_ERROR) errStr = "NO_ERROR";

            found = true;


            this._log.warn("gl error [" + this.canvas.id + "]: ", str, error, errStr);

            if (this.canvas.id.contains("glGuiCanvas"))
                if (!this._loggedGlError)
                {
                    this.patch.printTriggerStack();
                    this._log.stack("glerror");
                    this._loggedGlError = true;
                }
        }
        error = this.gl.getError();

        return found;
    }

    saveScreenshot(filename, cb, pw, ph, noclearalpha)
    {
        this.patch.renderOneFrame();

        let w = this.canvas.clientWidth * this.pixelDensity;
        let h = this.canvas.clientHeight * this.pixelDensity;

        if (pw)
        {
            this.canvas.width = pw;
            w = pw;
        }
        if (ph)
        {
            this.canvas.height = ph;
            h = ph;
        }

        function padLeft(nr, n, str)
        {
            return Array(n - String(nr).length + 1).join(str || "0") + nr;
        }

        const d = new Date();

        const dateStr = "".concat(String(d.getFullYear()) + String(d.getMonth() + 1) + String(d.getDate()), "_").concat(padLeft(d.getHours(), 2)).concat(padLeft(d.getMinutes(), 2)).concat(padLeft(d.getSeconds(), 2));

        if (!filename) filename = "cables_" + dateStr + ".png";
        else filename += ".png";

        this.patch.cgl.screenShot(function (blob)
        {
            this.canvas.width = w;
            this.canvas.height = h;

            if (blob)
            {
                const anchor = document.createElement("a");

                anchor.download = filename;
                anchor.href = URL.createObjectURL(blob);

                setTimeout(function ()
                {
                    anchor.click();
                    if (cb) cb(blob);
                }, 100);
            }
            else
            {
                this._log.log("screenshot: no blob");
            }
        }.bind(this), noclearalpha);
    }

    _dispose()
    {
        this._simpleShader.dispose();
        this.gl = null;
    }
}


Context.prototype.popShader = Context.prototype.setPreviousShader;
Context.prototype.setShader = Context.prototype.pushShader;

/**
 * execute the callback next frame, once
 * @function addNextFrameOnceCallback
 * @memberof Context
 * @instance
 * @param {function} cb
 */
Context.prototype.addNextFrameOnceCallback = function (cb)
{
    if (cb && this._onetimeCallbacks.indexOf(cb) == -1) this._onetimeCallbacks.push(cb);
};

// state depthtest

/**
 * push depth testing enabled state
 * @function pushDepthTest
 * @param {Boolean} enabled
 * @memberof Context
 * @instance
 */
Context.prototype._stackDepthTest = [];
Context.prototype.pushDepthTest = function (b)
{
    this._stackDepthTest.push(b);
    if (!b) this.gl.disable(this.gl.DEPTH_TEST);
    else this.gl.enable(this.gl.DEPTH_TEST);
};
/**
 * current state of depth testing
 * @function stateCullFace
 * @returns {Boolean} enabled
 * @memberof Context
 * @instance
 */
Context.prototype.stateDepthTest = function ()
{
    return this._stackDepthTest[this._stackDepthTest.length - 1];
};

/**
 * pop depth testing state
 * @function popCullFace
 * @memberof Context
 * @instance
 */
Context.prototype.popDepthTest = function ()
{
    this._stackDepthTest.pop();

    if (!this._stackDepthTest[this._stackDepthTest.length - 1]) this.gl.disable(this.gl.DEPTH_TEST);
    else this.gl.enable(this.gl.DEPTH_TEST);
};

// --------------------------------------
// state depthwrite

/**
 * push depth write enabled state
 * @function pushDepthTest
 * @param {Boolean} enabled
 * @memberof Context
 * @instance
 */
Context.prototype._stackDepthWrite = [];
Context.prototype.pushDepthWrite = function (b)
{
    b = b || false;
    this._stackDepthWrite.push(b);
    this.gl.depthMask(b);
};

/**
 * current state of depth writing
 * @function stateDepthWrite
 * @returns {Boolean} enabled
 * @memberof Context
 * @instance
 */
Context.prototype.stateDepthWrite = function ()
{
    return this._stackDepthWrite[this._stackDepthWrite.length - 1];
};

/**
 * pop depth writing state
 * @function popDepthWrite
 * @memberof Context
 * @instance
 */
Context.prototype.popDepthWrite = function ()
{
    this._stackDepthWrite.pop();
    this.gl.depthMask(this._stackDepthWrite[this._stackDepthWrite.length - 1] || false);
};


// --------------------------------------
// state CullFace

Context.prototype._stackCullFace = [];

/**
 * push face culling face enabled state
 * @function pushCullFace
 * @param {Boolean} b enabled
 * @memberof Context
 * @instance
 */
Context.prototype.pushCullFace = function (b)
{
    this._stackCullFace.push(b);

    if (b) this.gl.enable(this.gl.CULL_FACE);
    else this.gl.disable(this.gl.CULL_FACE);
};

/**
 * current state of face culling
 * @function stateCullFace
 * @returns {Boolean} enabled
 * @memberof Context
 * @instance
 */
Context.prototype.stateCullFace = function ()
{
    return this._stackCullFace[this._stackCullFace.length - 1];
};

/**
 * pop face culling enabled state
 * @function popCullFace
 * @memberof Context
 * @instance
 */
Context.prototype.popCullFace = function ()
{
    this._stackCullFace.pop();

    if (this._stackCullFace[this._stackCullFace.length - 1]) this.gl.enable(this.gl.CULL_FACE);
    else this.gl.disable(this.gl.CULL_FACE);
};


// --------------------------------------
// state CullFace Facing


/**
 * push face culling face side
 * @function pushCullFaceFacing
 * @param {Number} cgl.gl.FRONT_AND_BACK, cgl.gl.BACK or cgl.gl.FRONT
 * @memberof Context
 * @instance
 */
Context.prototype._stackCullFaceFacing = [];
Context.prototype.pushCullFaceFacing = function (b)
{
    this._stackCullFaceFacing.push(b);
    this.gl.cullFace(this._stackCullFaceFacing[this._stackCullFaceFacing.length - 1]);
};

/**
 * current state of face culling side
 * @function stateCullFaceFacing
 * @returns {Boolean} enabled
 * @memberof Context
 * @instance
 */
Context.prototype.stateCullFaceFacing = function ()
{
    return this._stackCullFaceFacing[this._stackCullFaceFacing.length - 1];
};

/**
 * pop face culling face side
 * @function popCullFaceFacing
 * @memberof Context
 * @instance
 */
Context.prototype.popCullFaceFacing = function ()
{
    this._stackCullFaceFacing.pop();
    if (this._stackCullFaceFacing.length > 0) this.gl.cullFace(this._stackCullFaceFacing[this._stackCullFaceFacing.length - 1]);
};


// --------------------------------------
// state depthfunc

Context.prototype._stackDepthFunc = [];

/**
 * enable / disable depth testing
 * like `gl.depthFunc(boolean);`
 * @function pushDepthFunc
 * @memberof Context
 * @instance
 * @param {Boolean} f depthtesting
 */
Context.prototype.pushDepthFunc = function (f)
{
    this._stackDepthFunc.push(f);
    this.gl.depthFunc(f);
};

/**
 * current state of blend
 * @function stateDepthFunc
 * @memberof Context
 * @instance
 * @returns {Boolean} depth testing enabled/disabled
 */
Context.prototype.stateDepthFunc = function ()
{
    if (this._stackDepthFunc.length > 0) return this._stackDepthFunc[this._stackDepthFunc.length - 1];
    return false;
};

/**
 * pop depth testing and set the previous state
 * @function popDepthFunc
 * @memberof Context
 * @instance
 */
Context.prototype.popDepthFunc = function ()
{
    this._stackDepthFunc.pop();
    if (this._stackDepthFunc.length > 0) this.gl.depthFunc(this._stackDepthFunc[this._stackDepthFunc.length - 1]);
};

// --------------------------------------
// state blending

Context.prototype._stackBlend = [];

/**
 * enable / disable blend
 * like gl.enable(gl.BLEND); / gl.disable(gl.BLEND);
 * @function pushBlend
 * @memberof Context
 * @instance
 * @param {boolean} b blending
 */
Context.prototype.pushBlend = function (b)
{
    this._stackBlend.push(b);
    if (!b) this.gl.disable(this.gl.BLEND);
    else this.gl.enable(this.gl.BLEND);
};

/**
 * pop blend state and set the previous state
 * @function popBlend
 * @memberof Context
 * @instance
 */
Context.prototype.popBlend = function ()
{
    this._stackBlend.pop();

    if (!this._stackBlend[this._stackBlend.length - 1]) this.gl.disable(this.gl.BLEND);
    else this.gl.enable(this.gl.BLEND);
};

/**
 * current state of blend
 * @function stateBlend
 * @returns {boolean} blending enabled/disabled
 * @memberof Context
 * @instance
 */
Context.prototype.stateBlend = function ()
{
    return this._stackBlend[this._stackBlend.length - 1];
};

const BLENDS = {
    "BLEND_NONE": 0,
    "BLEND_NORMAL": 1,
    "BLEND_ADD": 2,
    "BLEND_SUB": 3,
    "BLEND_MUL": 4,
};

Context.prototype._stackBlendMode = [];
Context.prototype._stackBlendModePremul = [];

/**
 * push and switch to predefined blendmode (CONSTANTS.BLEND_MODES.BLEND_NONE,CONSTANTS.BLEND_MODES.BLEND_NORMAL,CONSTANTS.BLEND_MODES.BLEND_ADD,CONSTANTS.BLEND_MODES.BLEND_SUB,CONSTANTS.BLEND_MODES.BLEND_MUL)
 * @function pushBlendMode
 * @memberof Context
 * @instance
 * @param {Number} blendMode
 * @param {Boolean} premul premultiplied mode
 */
Context.prototype.pushBlendMode = function (blendMode, premul)
{
    this._stackBlendMode.push(blendMode);
    this._stackBlendModePremul.push(premul);

    const n = this._stackBlendMode.length - 1;

    this.pushBlend(this._stackBlendMode[n] !== constants_CONSTANTS.BLEND_MODES.BLEND_NONE);
    this._setBlendMode(this._stackBlendMode[n], this._stackBlendModePremul[n]);
};

/**
 * pop predefined blendmode / switch back to previous blendmode
 * @function popBlendMode
 * @memberof Context
 * @instance
 */
Context.prototype.popBlendMode = function ()
{
    this._stackBlendMode.pop();
    this._stackBlendModePremul.pop();

    const n = this._stackBlendMode.length - 1;

    this.popBlend(this._stackBlendMode[n] !== constants_CONSTANTS.BLEND_MODES.BLEND_NONE);

    if (n >= 0) this._setBlendMode(this._stackBlendMode[n], this._stackBlendModePremul[n]);
};


// --------------------------------------
// state stencil

Context.prototype._stackStencil = [];

/**
 * enable / disable stencil testing

* @function pushStencil
 * @memberof Context
 * @instance
 * @param {Boolean} b enable
 */
Context.prototype.pushStencil = function (b)
{
    this._stackStencil.push(b);
    if (!b) this.gl.disable(this.gl.STENCIL_TEST);
    else this.gl.enable(this.gl.STENCIL_TEST);
};

/**
 * pop stencil test state and set the previous state
 * @function popStencil
 * @memberof Context
 * @instance
 */
Context.prototype.popStencil = function ()
{
    this._stackStencil.pop();

    if (!this._stackStencil[this._stackStencil.length - 1]) this.gl.disable(this.gl.STENCIL_TEST);
    else this.gl.enable(this.gl.STENCIL_TEST);
};

// --------------------------------------


Context.prototype.glGetAttribLocation = function (prog, name)
{
    const l = this.gl.getAttribLocation(prog, name);
    // if (l == -1)
    // {
    //     this._log.warn("get attr loc -1 ", name);
    // }
    return l;
};


/**
 * should an op now draw helpermeshes
 * @function shouldDrawHelpers
 * @memberof Context
 * @param op
 * @instance
 */
Context.prototype.shouldDrawHelpers = function (op)
{
    if (this.tempData.shadowPass) return false;
    if (!op.patch.isEditorMode()) return false;

    // const fb = this.getCurrentFrameBuffer();
    // if (fb && fb.getWidth)
    // {
    //     const fbshould = this.canvasWidth / this.canvasHeight == fb.getWidth() / fb.getHeight();
    //     if (!fbshould) return false;
    // }

    return gui.shouldDrawOverlay;// || (CABLES.UI.renderHelperCurrent && op.isCurrentUiOp());
};

Context.prototype._setBlendMode = function (blendMode, premul)
{
    const gl = this.gl;

    if (blendMode == constants_CONSTANTS.BLEND_MODES.BLEND_NONE)
    {
        // this.gl.disable(this.gl.BLEND);
    }
    else if (blendMode == constants_CONSTANTS.BLEND_MODES.BLEND_ADD)
    {
        if (premul)
        {
            gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
            gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ONE, gl.ONE);
        }
        else
        {
            gl.blendEquation(gl.FUNC_ADD);
            gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
        }
    }
    else if (blendMode == constants_CONSTANTS.BLEND_MODES.BLEND_SUB)
    {
        if (premul)
        {
            gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
            gl.blendFuncSeparate(gl.ZERO, gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ONE_MINUS_SRC_ALPHA);
        }
        else
        {
            gl.blendEquation(gl.FUNC_ADD);
            gl.blendFunc(gl.ZERO, gl.ONE_MINUS_SRC_COLOR);
        }
    }
    else if (blendMode == constants_CONSTANTS.BLEND_MODES.BLEND_MUL)
    {
        if (premul)
        {
            gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
            gl.blendFuncSeparate(gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA);
        }
        else
        {
            gl.blendEquation(gl.FUNC_ADD);
            gl.blendFunc(gl.ZERO, gl.SRC_COLOR);
        }
    }
    else if (blendMode == constants_CONSTANTS.BLEND_MODES.BLEND_NORMAL)
    {
        if (premul)
        {
            gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
            gl.blendFuncSeparate(gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
        }
        else
        {
            gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD);
            gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
        }
    }
    else
    {
        this._log.log("setblendmode: unknown blendmode");
    }
};

Context.prototype.createMesh = function (geom, options)
{
    if (CABLES.UTILS.isNumeric(options))options = { "glPrimitive": options }; // old constructor fallback...
    return new CGL.Mesh(this, geom, options);
};


/**
 * set cursor
 * @function setCursor
 * @memberof Context
 * @instance
 * @param {String} str css cursor string
 */
Context.prototype.setCursor = function (str)
{
    this._cursor = str;
};

/**
 * enable a webgl extension
 * @function enableExtension
 * @memberof Context
 * @instance
 * @param {String} name extension name
 * @returns {Object} extension object or null
 */
Context.prototype.enableExtension = function (name)
{
    if (!this.gl) return null;

    if (this._enabledExtensions.hasOwnProperty(name))
        return this._enabledExtensions[name];

    const o = this.gl.getExtension(name);
    this._enabledExtensions[name] = o;

    if (!o)
        this._log.warn("[cgl_state] extension not available " + name);
    // else
        // this._log.log("enabled extension", name);

    return o;
};

Context.prototype.checkTextureSize = function (x)
{
    x = x || 1;
    x = Math.floor(x);
    x = Math.min(x, this.maxTexSize);
    x = Math.max(x, 1);
    return x;
};





;// CONCATENATED MODULE: ./src/core/core_variable.js


/**
 * @type {Object}
 * @name PatchVariable
 * @param {String} name
 * @param {String|Number} value
 * @memberof Patch
 * @constructor
 */
class PatchVariable extends Events
{
    constructor(name, val, type)
    {
        super();
        this._name = name;
        this.type = type;
        this.setValue(val);
    }

    /**
     * keeping this for backwards compatibility in older
     * exports before using eventtarget
     *
     * @param cb
     */
    addListener(cb)
    {
        this.on("change", cb, "var");
    }

    /**
     * @function Variable.getValue
     * @memberof PatchVariable
     * @returns {String|Number|Boolean}
     */
    getValue()
    {
        return this._v;
    }

    /**
     * @function getName
     * @memberof PatchVariable
     * @instance
     * @returns {String|Number|Boolean}
     * @function
     */
    getName()
    {
        return this._name;
    }

    /**
     * @function setValue
     * @memberof PatchVariable
     * @instance
     * @param v
     * @returns {String|Number|Boolean}
     * @function
     */
    setValue(v)
    {
        this._v = v;
        this.emitEvent("change", v, this);
    }
}

/* harmony default export */ const core_variable = (PatchVariable);

;// CONCATENATED MODULE: ./src/core/core_patch.js












/**
 * Patch class, contains all operators,values,links etc. manages loading and running of the whole patch
 *
 * see {@link PatchConfig}
 *
 * @namespace external:CABLES#Patch
 * @hideconstructor
 * @param {PatchConfig} cfg The configuration object.
 * @class
 * @example
 * CABLES.patch=new CABLES.Patch(
 * {
 *     patch:pStr,
 *     glCanvasId:'glcanvas',
 *     glCanvasResizeToWindow:true,
 *     canvas:{powerPreference:"high-performance"},
 *     prefixAssetPath:'/assets/',
 *     prefixJsPath:'/js/',
 *     onError:function(e){console.log(e);}
 *     glslPrecision:'highp'
 * });
 */

class Patch extends EventTarget
{
// const Patch(cfg)
    constructor(cfg)
    {
        super();
        // EventTarget.apply(this);

        this._log = new Logger("core_patch", { "onError": cfg.onError });
        this.ops = [];
        this.settings = {};
        this.config = cfg ||
        {
            "glCanvasResizeToWindow": false,
            "prefixAssetPath": "",
            "prefixJsPath": "",
            "silent": true,
            "onError": null,
            "onFinishedLoading": null,
            "onFirstFrameRendered": null,
            "onPatchLoaded": null,
            "fpsLimit": 0
        };
        this.timer = new Timer();
        this.freeTimer = new Timer();
        this.animFrameOps = [];
        this.animFrameCallbacks = [];
        this.gui = false;
        CABLES.logSilent = this.silent = true;
        this.profiler = null;
        this.aborted = false;
        this._crashedOps = [];
        this._renderOneFrame = false;
        this._animReq = null;
        this._opIdCache = {};
        this._triggerStack = [];
        this.storeObjNames = false; // remove after may release

        this.loading = new LoadingStatus(this);

        this._volumeListeners = [];
        this._paused = false;
        this._frameNum = 0;
        this.onOneFrameRendered = null;
        this.namedTriggers = {};

        this._origData = null;
        this._frameNext = 0;
        this._frameInterval = 0;
        this._lastFrameTime = 0;
        this._frameWasdelayed = true;
        this.tempData = this.frameStore = {};
        this.deSerialized = false;
        this.reqAnimTimeStamp = 0;

        this.cgCanvas = null;

        if (!(function () { return !this; }())) console.log("not in strict mode: core patch");

        this._isLocal = document.location.href.indexOf("file:") === 0;

        if (this.config.hasOwnProperty("silent")) this.silent = CABLES.logSilent = this.config.silent;
        if (!this.config.hasOwnProperty("doRequestAnimation")) this.config.doRequestAnimation = true;

        if (!this.config.prefixAssetPath) this.config.prefixAssetPath = "";
        if (!this.config.prefixJsPath) this.config.prefixJsPath = "";
        if (!this.config.masterVolume) this.config.masterVolume = 1.0;

        this._variables = {};
        this._variableListeners = [];
        this.vars = {};
        if (cfg && cfg.vars) this.vars = cfg.vars; // vars is old!

        this.cgl = new Context(this);
        this.cgp = null;

        this._subpatchOpCache = {};

        this.cgl.setCanvas(this.config.glCanvasId || this.config.glCanvas || "glcanvas");
        if (this.config.glCanvasResizeToWindow === true) this.cgl.setAutoResize("window");
        if (this.config.glCanvasResizeToParent === true) this.cgl.setAutoResize("parent");
        this.loading.setOnFinishedLoading(this.config.onFinishedLoading);

        if (this.cgl.aborted) this.aborted = true;
        if (this.cgl.silent) this.silent = true;

        this.freeTimer.play();
        this.exec();

        if (!this.aborted)
        {
            if (this.config.patch)
            {
                this.deSerialize(this.config.patch);
            }
            else if (this.config.patchFile)
            {
                ajax(
                    this.config.patchFile,
                    (err, _data) =>
                    {
                        try
                        {
                            const data = JSON.parse(_data);
                            if (err)
                            {
                                const txt = "";
                                this._log.error("err", err);
                                this._log.error("data", data);
                                this._log.error("data", data.msg);
                                return;
                            }
                            this.deSerialize(data);
                        }
                        catch (e)
                        {
                            this._log.error("could not load/parse patch ", e);
                        }
                    }
                );
            }
            this.timer.play();
        }

    console.log("made with https://cables.gl"); // eslint-disable-line
    }

    isPlaying()
    {
        return !this._paused;
    }

    isRenderingOneFrame()
    {
        return this._renderOneFrame;
    }


    renderOneFrame()
    {
        this._paused = true;
        this._renderOneFrame = true;
        this.exec();
        this._renderOneFrame = false;
    }

    /**
 * current number of frames per second
 * @function getFPS
 * @memberof Patch
 * @instance
 * @return {Number} fps
 */
    getFPS()
    {
        this._log.error("deprecated getfps");
        return 0;
    }

    /**
 * returns true if patch is opened in editor/gui mode
 * @function isEditorMode
 * @memberof Patch
 * @instance
 * @return {Boolean} editor mode
 */
    isEditorMode()
    {
        return this.config.editorMode === true;
    }

    /**
 * pauses patch execution
 * @function pause
 * @memberof Patch
 * @instance
 */
    pause()
    {
        cancelAnimationFrame(this._animReq);
        this.emitEvent("pause");
        this._animReq = null;
        this._paused = true;
        this.freeTimer.pause();
    }

    /**
 * resumes patch execution
 * @function resume
 * @memberof Patch
 * @instance
 */
    resume()
    {
        if (this._paused)
        {
            cancelAnimationFrame(this._animReq);
            this._paused = false;
            this.freeTimer.play();
            this.emitEvent("resume");
            this.exec();
        }
    }

    /**
 * set volume [0-1]
 * @function setVolume
 * @param {Number} v volume
 * @memberof Patch
 * @instance
 */
    setVolume(v)
    {
        this.config.masterVolume = v;
        for (let i = 0; i < this._volumeListeners.length; i++) this._volumeListeners[i].onMasterVolumeChanged(v);
    }


    /**
 * get asset path
 * @function getAssetPath
 * @memberof Patch
 * @param patchId
 * @instance
 */
    getAssetPath(patchId = null)
    {
        if (this.config.hasOwnProperty("assetPath"))
        {
            return this.config.assetPath;
        }
        else if (this.isEditorMode())
        {
            let id = patchId || gui.project()._id;
            return "/assets/" + id + "/";
        }
        else if (document.location.href.indexOf("cables.gl") > 0 || document.location.href.indexOf("cables.local") > 0)
        {
            const parts = document.location.pathname.split("/");
            let id = patchId || parts[parts.length - 1];
            return "/assets/" + id + "/";
        }
        else
        {
            return "assets/";
        }
    }

    /**
 * get js path
 * @function getJsPath
 * @memberof Patch
 * @instance
 */
    getJsPath()
    {
        if (this.config.hasOwnProperty("jsPath"))
        {
            return this.config.jsPath;
        }
        else
        {
            return "js/";
        }
    }

    /**
 * get url/filepath for a filename
 * this uses prefixAssetpath in exported patches
 * @function getFilePath
 * @memberof Patch
 * @instance
 * @param {String} filename
 * @return {String} url
 */
    getFilePath(filename)
    {
        if (!filename) return filename;
        filename = String(filename);
        if (filename.indexOf("https:") === 0 || filename.indexOf("http:") === 0) return filename;
        if (filename.indexOf("data:") === 0) return filename;
        if (filename.indexOf("file:") === 0) return filename;
        filename = filename.replace("//", "/");
        if (filename.startsWith(this.config.prefixAssetPath)) filename = filename.replace(this.config.prefixAssetPath, "");
        return this.config.prefixAssetPath + filename + (this.config.suffixAssetPath || "");
    }

    clear()
    {
        this.emitEvent("patchClearStart");
        this.cgl.TextureEffectMesh = null;
        this.animFrameOps.length = 0;
        this.timer = new Timer();
        while (this.ops.length > 0) this.deleteOp(this.ops[0].id);

        this._opIdCache = {};
        this.emitEvent("patchClearEnd");
    }




    createOp(identifier, id, opName = null)
    {
        let op = null;
        let objName = "";

        try
        {
            if (!identifier)
            {
                console.error("createop identifier false", identifier);
                console.log((new Error()).stack);
                return;
            }
            if (identifier.indexOf("Ops.") === -1)
            {
                // this should be a uuid, not a namespace
                // creating ops by id should be the default way from now on!
                const opId = identifier;



                if (CABLES.OPS[opId])
                {
                    objName = CABLES.OPS[opId].objName;
                    op = new CABLES.OPS[opId].f(this, objName, id, opId);
                    op.opId = opId;
                }
                else
                {
                    if (opName)
                    {
                        identifier = opName;
                        this._log.warn("could not find op by id: " + opId);
                    }
                    else
                    {
                        throw new Error("could not find op by id: " + opId, { "cause": "opId:" + opId });
                    }
                }
            }

            if (!op)
            {
                // fallback: create by objname!
                objName = identifier;
                const parts = identifier.split(".");
                const opObj = Patch.getOpClass(objName);

                if (!opObj)
                {
                    this.emitEvent("criticalError", { "title": "unknown op" + objName, "text": "unknown op: " + objName });

                    this._log.error("unknown op: " + objName);
                    throw new Error("unknown op: " + objName);
                }
                else
                {
                    if (parts.length == 2) op = new window[parts[0]][parts[1]](this, objName, id);
                    else if (parts.length == 3) op = new window[parts[0]][parts[1]][parts[2]](this, objName, id);
                    else if (parts.length == 4) op = new window[parts[0]][parts[1]][parts[2]][parts[3]](this, objName, id);
                    else if (parts.length == 5) op = new window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]](this, objName, id);
                    else if (parts.length == 6) op = new window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]](this, objName, id);
                    else if (parts.length == 7) op = new window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]](this, objName, id);
                    else if (parts.length == 8) op = new window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]][parts[7]](this, objName, id);
                    else if (parts.length == 9) op = new window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]][parts[7]][parts[8]](this, objName, id);
                    else if (parts.length == 10) op = new window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]][parts[7]][parts[8]][parts[9]](this, objName, id);
                    else console.log("parts.length", parts.length);
                }

                if (op)
                {
                    op.opId = null;
                    for (const i in CABLES.OPS)
                    {
                        if (CABLES.OPS[i].objName == objName) op.opId = i;
                    }
                }
            }
        }
        catch (e)
        {
            this._crashedOps.push(objName);

            this._log.error("[instancing error] " + objName, e);

            if (!this.isEditorMode())
            {
                this._log.error("INSTANCE_ERR", "Instancing Error: " + objName, e);
                // throw new Error("instancing error 1" + objName);
            }
        }

        if (op)
        {
            op._objName = objName;
            op.patch = this;
        }
        else
        {
            this._log.log("no op was created!?", identifier, id);
        }
        return op;
    }

    /**
     * create a new op in patch
     * @function addOp
     * @memberof Patch
     * @instance
     * @param {string} opIdentifier uuid or name, e.g. Ops.Math.Sum
     * @param {Object} uiAttribs Attributes
     * @param {string} id
     * @param {boolean} fromDeserialize
     * @param {string} opName e.g. Ops.Math.Sum
     * @example
     * // add invisible op
     * patch.addOp('Ops.Math.Sum', { showUiAttribs: false });
     */
    addOp(opIdentifier, uiAttribs, id, fromDeserialize, opName)
    {
        const op = this.createOp(opIdentifier, id, opName);

        if (op)
        {
            uiAttribs = uiAttribs || {};
            if (uiAttribs.hasOwnProperty("errors")) delete uiAttribs.errors;
            if (uiAttribs.hasOwnProperty("error")) delete uiAttribs.error;
            uiAttribs.subPatch = uiAttribs.subPatch || 0;

            op.setUiAttribs(uiAttribs);
            if (op.onCreate) op.onCreate();

            if (op.hasOwnProperty("onAnimFrame")) this.addOnAnimFrame(op);
            if (op.hasOwnProperty("onMasterVolumeChanged")) this._volumeListeners.push(op);

            if (this._opIdCache[op.id])
            {
                this._log.warn("opid with id " + op.id + " already exists in patch!");
                this.deleteOp(op.id); // strange with subpatch ops: why is this needed, somehow ops get added twice ???.....
                // return;
            }

            this.ops.push(op);
            this._opIdCache[op.id] = op;

            if (this._subPatchCacheAdd) this._subPatchCacheAdd(uiAttribs.subPatch, op);
            this.emitEvent("onOpAdd", op, fromDeserialize);

            if (op.init) op.init();

            op.emitEvent("init", fromDeserialize);
        }
        else
        {
            this._log.error("addop: op could not be created: ", opIdentifier);
        }

        return op;
    }

    addOnAnimFrame(op)
    {
        for (let i = 0; i < this.animFrameOps.length; i++) if (this.animFrameOps[i] == op) { return; }

        this.animFrameOps.push(op);
    }

    removeOnAnimFrame(op)
    {
        for (let i = 0; i < this.animFrameOps.length; i++)
        {
            if (this.animFrameOps[i] == op)
            {
                this.animFrameOps.splice(i, 1);
                return;
            }
        }
    }

    addOnAnimFrameCallback(cb)
    {
        this.animFrameCallbacks.push(cb);
    }

    removeOnAnimCallback(cb)
    {
        for (let i = 0; i < this.animFrameCallbacks.length; i++)
        {
            if (this.animFrameCallbacks[i] == cb)
            {
                this.animFrameCallbacks.splice(i, 1);
                return;
            }
        }
    }

    deleteOp(opid, tryRelink, reloadingOp)
    {
        let found = false;
        for (const i in this.ops)
        {
            if (this.ops[i].id == opid)
            {
                const op = this.ops[i];
                let reLinkP1 = null;
                let reLinkP2 = null;

                if (op)
                {
                    found = true;
                    if (tryRelink)
                    {
                        if (op.portsIn.length > 0 && op.portsIn[0].isLinked() && (op.portsOut.length > 0 && op.portsOut[0].isLinked()))
                        {
                            if (op.portsIn[0].getType() == op.portsOut[0].getType() && op.portsIn[0].links[0])
                            {
                                reLinkP1 = op.portsIn[0].links[0].getOtherPort(op.portsIn[0]);
                                reLinkP2 = op.portsOut[0].links[0].getOtherPort(op.portsOut[0]);
                            }
                        }
                    }

                    const opToDelete = this.ops[i];
                    opToDelete.removeLinks();

                    if (this.onDelete)
                    {
                        // todo: remove
                        this._log.warn("deprecated this.onDelete", this.onDelete);
                        this.onDelete(opToDelete);
                    }

                    this.ops.splice(i, 1);
                    opToDelete.emitEvent("delete", opToDelete);
                    this.emitEvent("onOpDelete", opToDelete, reloadingOp);

                    if (this.clearSubPatchCache) this.clearSubPatchCache(opToDelete.uiAttribs.subPatch);

                    if (opToDelete.onDelete) opToDelete.onDelete(reloadingOp);
                    opToDelete.cleanUp();

                    if (reLinkP1 !== null && reLinkP2 !== null)
                    {
                        this.link(reLinkP1.op, reLinkP1.getName(), reLinkP2.op, reLinkP2.getName());
                    }

                    delete this._opIdCache[opid];
                    break;
                }
            }
        }

        if (!found) this._log.warn("core patch deleteop: not found...", opid);
    }

    getFrameNum()
    {
        return this._frameNum;
    }

    emitOnAnimFrameEvent(time, delta)
    {
        time = time || this.timer.getTime();

        for (let i = 0; i < this.animFrameCallbacks.length; ++i)
            if (this.animFrameCallbacks[i])
                this.animFrameCallbacks[i](time, this._frameNum, delta);

        for (let i = 0; i < this.animFrameOps.length; ++i)
            if (this.animFrameOps[i].onAnimFrame)
                this.animFrameOps[i].onAnimFrame(time, this._frameNum, delta);
    }

    renderFrame(timestamp)
    {
        this.timer.update(this.reqAnimTimeStamp);
        this.freeTimer.update(this.reqAnimTimeStamp);
        const time = this.timer.getTime();
        const startTime = performance.now();
        this.cgl.frameStartTime = this.timer.getTime();

        const delta = timestamp - this.reqAnimTimeStamp || timestamp;

        this.emitOnAnimFrameEvent(null, delta);

        this.cgl.profileData.profileFrameDelta = delta;
        this.reqAnimTimeStamp = timestamp;
        this.cgl.profileData.profileOnAnimFrameOps = performance.now() - startTime;

        this.emitEvent("onRenderFrame", time);

        this._frameNum++;
        if (this._frameNum == 1)
        {
            if (this.config.onFirstFrameRendered) this.config.onFirstFrameRendered();
        }
    }

    exec(timestamp)
    {
        if (!this._renderOneFrame && (this._paused || this.aborted)) return;
        this.emitEvent("reqAnimFrame");
        cancelAnimationFrame(this._animReq);

        this.config.fpsLimit = this.config.fpsLimit || 0;
        if (this.config.fpsLimit)
        {
            this._frameInterval = 1000 / this.config.fpsLimit;
        }

        const now = CABLES.now();
        const frameDelta = now - this._frameNext;

        if (this.isEditorMode())
        {
            if (!this._renderOneFrame)
            {
                if (now - this._lastFrameTime >= 500 && this._lastFrameTime !== 0 && !this._frameWasdelayed)
                {
                    this._lastFrameTime = 0;
                    setTimeout(this.exec.bind(this), 500);
                    this.emitEvent("renderDelayStart");
                    this._frameWasdelayed = true;
                    return;
                }
            }
        }

        if (this._renderOneFrame || this.config.fpsLimit === 0 || frameDelta > this._frameInterval || this._frameWasdelayed)
        {
            this.renderFrame(timestamp);

            if (this._frameInterval) this._frameNext = now - (frameDelta % this._frameInterval);
        }

        if (this._frameWasdelayed)
        {
            this.emitEvent("renderDelayEnd");
            this._frameWasdelayed = false;
        }

        if (this._renderOneFrame)
        {
            if (this.onOneFrameRendered) this.onOneFrameRendered(); // todo remove everywhere and use propper event...
            this.emitEvent("renderedOneFrame");
            this._renderOneFrame = false;
        }


        if (this.config.doRequestAnimation) this._animReq = this.cgl.canvas.ownerDocument.defaultView.requestAnimationFrame(this.exec.bind(this));
    }

    /**
     * link two ops/ports
     * @function link
     * @memberof Patch
     * @instance
     * @param {Op} op1
     * @param {String} port1Name
     * @param {Op} op2
     * @param {String} port2Name
     * @param {boolean} lowerCase
     * @param {boolean} fromDeserialize
     */
    link(op1, port1Name, op2, port2Name, lowerCase, fromDeserialize)
    {
        if (!op1) return this._log.warn("link: op1 is null ");
        if (!op2) return this._log.warn("link: op2 is null");

        const port1 = op1.getPort(port1Name, lowerCase);
        const port2 = op2.getPort(port2Name, lowerCase);

        if (!port1) return op1._log.warn("port1 not found! " + port1Name + " (" + op1.objName + ")");
        if (!port2) return op1._log.warn("port2 not found! " + port2Name + " of " + op2.name + "(" + op2.objName + ")", op2);

        if (!port1.shouldLink(port1, port2) || !port2.shouldLink(port1, port2)) return false;

        if (Link.canLink(port1, port2))
        {
            const link = new Link(this);
            link.link(port1, port2);

            this.emitEvent("onLink", port1, port2, link, fromDeserialize);
            return link;
        }
    }

    serialize(options)
    {
        const obj = {};

        options = options || {};
        obj.ops = [];
        obj.settings = this.settings;
        for (const i in this.ops)
        {
            const op = this.ops[i];
            if (op && op.getSerialized)obj.ops.push(op.getSerialized());
        }

        cleanJson(obj);

        if (options.asObject) return obj;
        return JSON.stringify(obj);
    }

    getOpsByRefId(refId)
    {
        const perf = CABLES.UI.uiProfiler.start("[corepatchetend] getOpsByRefId");
        const refOps = [];
        const ops = gui.corePatch().ops;
        for (let i = 0; i < ops.length; i++)
            if (ops[i].storage && ops[i].storage.ref == refId) refOps.push(ops[i]);
        perf.finish();
        return refOps;
    }

    getOpById(opid)
    {
        return this._opIdCache[opid];
    }

    getOpsByName(name)
    {
        // TODO: is this still needed ? unclear behaviour....
        const arr = [];
        for (const i in this.ops)
            if (this.ops[i].name == name) arr.push(this.ops[i]);
        return arr;
    }

    getOpsByObjName(name)
    {
        const arr = [];
        for (const i in this.ops)
            if (this.ops[i].objName == name) arr.push(this.ops[i]);
        return arr;
    }

    getOpsByOpId(opid)
    {
        const arr = [];
        for (const i in this.ops)
            if (this.ops[i].opId == opid) arr.push(this.ops[i]);
        return arr;
    }

    loadLib(which)
    {
        ajaxSync(
            "/ui/libs/" + which + ".js",
            (err, res) =>
            {
                const se = document.createElement("script");
                se.type = "text/javascript";
                se.text = res;
                document.getElementsByTagName("head")[0].appendChild(se);
            },
            "GET",
        );
    }

    getSubPatchOpsByName(patchId, objName)
    {
        const arr = [];
        for (const i in this.ops)
            if (this.ops[i].uiAttribs && this.ops[i].uiAttribs.subPatch == patchId && this.ops[i].objName == objName)
                arr.push(this.ops[i]);

        return arr;
    }

    getSubPatchOp(patchId, objName)
    {
        return this.getFirstSubPatchOpByName(patchId, objName);
    }

    getFirstSubPatchOpByName(patchId, objName)
    {
        for (const i in this.ops)
            if (this.ops[i].uiAttribs && this.ops[i].uiAttribs.subPatch == patchId && this.ops[i].objName == objName)
                return this.ops[i];

        return false;
    }

    _addLink(opinid, opoutid, inName, outName)
    {
        return this.link(this.getOpById(opinid), inName, this.getOpById(opoutid), outName, false, true);
    }

    deSerialize(obj, options)
    {
        options = options || { "genIds": false, "createRef": false };
        if (this.aborted) return;
        const newOps = [];
        const loadingId = this.loading.start("core", "deserialize");

        this.namespace = obj.namespace || "";
        this.name = obj.name || "";

        if (typeof obj === "string") obj = JSON.parse(obj);

        this.settings = obj.settings;

        this.emitEvent("patchLoadStart");

        obj.ops = obj.ops || [];

        if (window.logStartup)logStartup("add " + obj.ops.length + " ops... ");

        const addedOps = [];

        // add ops...
        for (let iop = 0; iop < obj.ops.length; iop++)
        {
            const start = CABLES.now();
            const opData = obj.ops[iop];
            let op = null;

            try
            {
                if (opData.opId) op = this.addOp(opData.opId, opData.uiAttribs, opData.id, true, opData.objName);
                else op = this.addOp(opData.objName, opData.uiAttribs, opData.id, true);
            }
            catch (e)
            {
                this._log.error("[instancing error] op data:", opData, e);
                // throw new Error("could not create op by id: <b>" + (opData.objName || opData.opId) + "</b> (" + opData.id + ")");
            }

            if (op)
            {
                addedOps.push(op);
                if (options.genIds) op.id = shortId();
                op.portsInData = opData.portsIn;
                op._origData = JSON.parse(JSON.stringify(opData));
                op.storage = opData.storage;
                // if (opData.hasOwnProperty("disabled"))op.setEnabled(!opData.disabled);

                for (const ipi in opData.portsIn)
                {
                    const objPort = opData.portsIn[ipi];
                    if (objPort && objPort.hasOwnProperty("name"))
                    {
                        const port = op.getPort(objPort.name);

                        if (port && (port.uiAttribs.display == "bool" || port.uiAttribs.type == "bool") && !isNaN(objPort.value)) objPort.value = objPort.value == true ? 1 : 0;
                        if (port && objPort.value !== undefined && port.type != CONSTANTS.OP.OP_PORT_TYPE_TEXTURE) port.set(objPort.value);

                        if (port)
                        {
                            port.deSerializeSettings(objPort);
                        }
                        else
                        {
                            // if (port.uiAttribs.hasOwnProperty("title"))
                            // {
                            //     op.preservedPortTitles = op.preservedPortTitles || {};
                            //     op.preservedPortTitles[port.name] = port.uiAttribs.title;
                            // }
                            op.preservedPortValues = op.preservedPortValues || {};
                            op.preservedPortValues[objPort.name] = objPort.value;
                        }
                    }
                }

                for (const ipo in opData.portsOut)
                {
                    const objPort = opData.portsOut[ipo];
                    if (objPort && objPort.hasOwnProperty("name"))
                    {
                        const port2 = op.getPort(objPort.name);

                        if (port2)
                        {
                            port2.deSerializeSettings(objPort);

                            if (port2.uiAttribs.hasOwnProperty("title"))
                            {
                                op.preservedPortTitles = op.preservedPortTitles || {};
                                op.preservedPortTitles[port2.name] = port2.uiAttribs.title;
                            }


                            if (port2.type != CONSTANTS.OP.OP_PORT_TYPE_TEXTURE && objPort.hasOwnProperty("value"))
                                port2.set(obj.ops[iop].portsOut[ipo].value);

                            if (objPort.expose) port2.setUiAttribs({ "expose": true });
                        }
                    }
                }
                newOps.push(op);
            }

            const timeused = Math.round(100 * (CABLES.now() - start)) / 100;
            if (!this.silent && timeused > 5) console.log("long op init ", obj.ops[iop].objName, timeused);
        }
        if (window.logStartup)logStartup("add ops done");

        for (const i in this.ops)
        {
            if (this.ops[i].onLoadedValueSet)
            {
                this.ops[i].onLoadedValueSet(this.ops[i]._origData);
                this.ops[i].onLoadedValueSet = null;
                this.ops[i]._origData = null;
            }
            this.ops[i].emitEvent("loadedValueSet");
        }

        if (window.logStartup)logStartup("creating links");

        if (options.opsCreated)options.opsCreated(addedOps);
        // create links...
        if (obj.ops)
        {
            for (let iop = 0; iop < obj.ops.length; iop++)
            {
                if (obj.ops[iop].portsIn)
                {
                    for (let ipi2 = 0; ipi2 < obj.ops[iop].portsIn.length; ipi2++)
                    {
                        if (obj.ops[iop].portsIn[ipi2] && obj.ops[iop].portsIn[ipi2].links)
                        {
                            for (let ili = 0; ili < obj.ops[iop].portsIn[ipi2].links.length; ili++)
                            {
                                const l = this._addLink(
                                    obj.ops[iop].portsIn[ipi2].links[ili].objIn,
                                    obj.ops[iop].portsIn[ipi2].links[ili].objOut,
                                    obj.ops[iop].portsIn[ipi2].links[ili].portIn,
                                    obj.ops[iop].portsIn[ipi2].links[ili].portOut);

                                // const took = performance.now - startTime;
                                // if (took > 100)console.log(obj().ops[iop].portsIn[ipi2].links[ili].objIn, obj.ops[iop].portsIn[ipi2].links[ili].objOut, took);
                            }
                        }
                    }
                }
                if (obj.ops[iop].portsOut)
                    for (let ipi2 = 0; ipi2 < obj.ops[iop].portsOut.length; ipi2++)
                        if (obj.ops[iop].portsOut[ipi2] && obj.ops[iop].portsOut[ipi2].links)
                        {
                            for (let ili = 0; ili < obj.ops[iop].portsOut[ipi2].links.length; ili++)
                            {
                                if (obj.ops[iop].portsOut[ipi2].links[ili])
                                {
                                    if (obj.ops[iop].portsOut[ipi2].links[ili].subOpRef)
                                    {
                                        // lost link
                                        const outOp = this.getOpById(obj.ops[iop].portsOut[ipi2].links[ili].objOut);
                                        let dstOp = null;
                                        let theSubPatch = 0;

                                        for (let i = 0; i < this.ops.length; i++)
                                        {
                                            if (
                                                this.ops[i].storage &&
                                                this.ops[i].storage.ref == obj.ops[iop].portsOut[ipi2].links[ili].subOpRef &&
                                                outOp.uiAttribs.subPatch == this.ops[i].uiAttribs.subPatch
                                            )
                                            {
                                                theSubPatch = this.ops[i].patchId.get();
                                                break;
                                            }
                                        }

                                        for (let i = 0; i < this.ops.length; i++)
                                        {
                                            if (
                                                this.ops[i].storage &&
                                                this.ops[i].storage.ref == obj.ops[iop].portsOut[ipi2].links[ili].refOp &&
                                                this.ops[i].uiAttribs.subPatch == theSubPatch)
                                            {
                                                dstOp = this.ops[i];
                                                break;
                                            }
                                        }

                                        if (!dstOp) this._log.warn("could not find op for lost link");
                                        else
                                        {
                                            const l = this._addLink(
                                                dstOp.id,
                                                obj.ops[iop].portsOut[ipi2].links[ili].objOut,

                                                obj.ops[iop].portsOut[ipi2].links[ili].portIn,
                                                obj.ops[iop].portsOut[ipi2].links[ili].portOut);
                                        }
                                    }
                                    else
                                    {
                                        const l = this._addLink(obj.ops[iop].portsOut[ipi2].links[ili].objIn, obj.ops[iop].portsOut[ipi2].links[ili].objOut, obj.ops[iop].portsOut[ipi2].links[ili].portIn, obj.ops[iop].portsOut[ipi2].links[ili].portOut);

                                        if (!l)
                                        {
                                            const op1 = this.getOpById(obj.ops[iop].portsOut[ipi2].links[ili].objIn);
                                            const op2 = this.getOpById(obj.ops[iop].portsOut[ipi2].links[ili].objOut);

                                            if (!op1)console.log("could not find link op1");
                                            if (!op2)console.log("could not find link op2");

                                            const p1Name = obj.ops[iop].portsOut[ipi2].links[ili].portIn;

                                            if (op1 && !op1.getPort(p1Name))
                                            {
                                                // console.log("PRESERVE port 1 not found", p1Name);

                                                op1.preservedPortLinks[p1Name] = op1.preservedPortLinks[p1Name] || [];
                                                op1.preservedPortLinks[p1Name].push(obj.ops[iop].portsOut[ipi2].links[ili]);
                                            }

                                            const p2Name = obj.ops[iop].portsOut[ipi2].links[ili].portOut;
                                            if (op2 && !op2.getPort(p2Name))
                                            {
                                                // console.log("PRESERVE port 2 not found", obj.ops[iop].portsOut[ipi2].links[ili].portOut);
                                                op2.preservedPortLinks[p1Name] = op2.preservedPortLinks[p1Name] || [];
                                                op2.preservedPortLinks[p1Name].push(obj.ops[iop].portsOut[ipi2].links[ili]);
                                            }
                                        }
                                    }
                                }
                            }
                        }
            }
        }

        if (window.logStartup)logStartup("calling ops onloaded");

        for (const i in this.ops)
        {
            if (this.ops[i].onLoaded)
            {
                // TODO: deprecate!!!
                this.ops[i].onLoaded();
                this.ops[i].onLoaded = null;
            }
        }

        if (window.logStartup)logStartup("initializing ops...");
        for (const i in this.ops)
        {
            if (this.ops[i].init)
            {
                try
                {
                    this.ops[i].init();
                    this.ops[i].init = null;
                }
                catch (e)
                {
                    console.error("op.init crash", e);
                }
            }
        }

        if (window.logStartup)logStartup("initializing vars...");

        if (this.config.variables)
            for (const varName in this.config.variables)
                this.setVarValue(varName, this.config.variables[varName]);

        if (window.logStartup)logStartup("initializing var ports");

        for (const i in this.ops)
        {
            this.ops[i].initVarPorts();
            delete this.ops[i].uiAttribs.pasted;
        }

        setTimeout(() => { this.loading.finished(loadingId); }, 100);

        if (this.config.onPatchLoaded) this.config.onPatchLoaded(this);

        this.deSerialized = true;
        this.emitEvent("patchLoadEnd", newOps, obj, options.genIds);
    }

    profile(enable)
    {
        this.profiler = new Profiler(this);
        for (const i in this.ops)
        {
            this.ops[i].profile(enable);
        }
    }

    // ----------------------

    /**
     * set variable value
     * @function setVariable
     * @memberof Patch
     * @instance
     * @param {String} name of variable
     * @param {Number|String|Boolean} val value
     */
    setVariable(name, val)
    {
        // if (this._variables.hasOwnProperty(name))
        if (this._variables[name] !== undefined)
        {
            this._variables[name].setValue(val);
        }
        else
        {
            this._log.warn("variable " + name + " not found!");
        }
    }

    _sortVars()
    {
        if (!this.isEditorMode()) return;
        const ordered = {};
        Object.keys(this._variables).sort(
            (a, b) =>
            { return a.localeCompare(b, "en", { "sensitivity": "base" }); }
        ).forEach((key) =>
        {
            ordered[key] = this._variables[key];
        });
        this._variables = ordered;
    }

    /**
     * has variable
     * @function hasVariable
     * @memberof Patch
     * @instance
     * @param {String} name of variable
     */
    hasVar(name)
    {
        return this._variables[name] !== undefined;

        // return this._variables.hasOwnProperty(name);
    }

    // used internally
    setVarValue(name, val, type)
    {
        if (this.hasVar(name))
        {
            this._variables[name].setValue(val);
        }
        else
        {
            this._variables[name] = new core_variable(name, val, type);
            this._sortVars();
            this.emitEvent("variablesChanged");
        }
        return this._variables[name];
    }

    // old?
    getVarValue(name, val)
    {
        if (this._variables.hasOwnProperty(name)) return this._variables[name].getValue();
    }

    /**
     * @function getVar
     * @memberof Patch
     * @instance
     * @param {String} name
     * @return {Variable} variable
     */
    getVar(name)
    {
        if (this._variables.hasOwnProperty(name)) return this._variables[name];
    }


    deleteVar(name)
    {
        for (let i = 0; i < this.ops.length; i++)
            for (let j = 0; j < this.ops[i].portsIn.length; j++)
                if (this.ops[i].portsIn[j].getVariableName() == name)
                    this.ops[i].portsIn[j].setVariable(null);

        delete this._variables[name];
        this.emitEvent("variableDeleted", name);
        this.emitEvent("variablesChanged");
    }

    /**
     * @function getVars
     * @memberof Patch
     * @instance
     * @param t
     * @return {Array<Variable>} variables
     * @function
     */
    getVars(t)
    {
        if (t === undefined) return this._variables;

        const vars = [];
        if (t == CABLES.OP_PORT_TYPE_STRING) t = "string";
        if (t == CABLES.OP_PORT_TYPE_VALUE) t = "number";
        if (t == CABLES.OP_PORT_TYPE_ARRAY) t = "array";
        if (t == CABLES.OP_PORT_TYPE_OBJECT) t = "object";

        for (const i in this._variables)
        {
            if (!this._variables[i].type || this._variables[i].type == t) vars.push(this._variables[i]);
        }
        return vars;
    }


    /**
     * @function preRenderOps
     * @memberof Patch
     * @instance
     * @description invoke pre rendering of ops
     * @function
     */
    preRenderOps()
    {
        this._log.log("prerendering...");

        for (let i = 0; i < this.ops.length; i++)
        {
            if (this.ops[i].preRender)
            {
                this.ops[i].preRender();
                this._log.log("prerender " + this.ops[i].objName);
            }
        }
    }

    /**
     * @function dispose
     * @memberof Patch
     * @instance
     * @description stop, dispose and cleanup patch
     */
    dispose()
    {
        this.pause();
        this.clear();
        this.cgl.dispose();
    }

    pushTriggerStack(p)
    {
        this._triggerStack.push(p);
    }

    popTriggerStack()
    {
        this._triggerStack.pop();
    }

    printTriggerStack()
    {
        if (this._triggerStack.length == 0)
        {
            // console.log("stack length", this._triggerStack.length); // eslint-disable-line
            return;
        }
        console.groupCollapsed( // eslint-disable-line
            "trigger port stack " + this._triggerStack[this._triggerStack.length - 1].op.objName + "." + this._triggerStack[this._triggerStack.length - 1].name,
        );

        const rows = [];
        for (let i = 0; i < this._triggerStack.length; i++)
        {
            rows.push(i + ". " + this._triggerStack[i].op.objName + " " + this._triggerStack[i].name);
        }

        console.table(rows); // eslint-disable-line
        console.groupEnd(); // eslint-disable-line
    }

    /**
     * returns document object of the patch could be != global document object when opening canvas ina popout window
     * @function getDocument
     * @memberof Patch
     * @instance
     * @return {Object} document
     */
    getDocument()
    {
        return this.cgl.canvas.ownerDocument;
    }
}

Patch.getOpClass = function (objName)
{
    const parts = objName.split(".");
    let opObj = null;

    try
    {
        if (parts.length == 2) opObj = window[parts[0]][parts[1]];
        else if (parts.length == 3) opObj = window[parts[0]][parts[1]][parts[2]];
        else if (parts.length == 4) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]];
        else if (parts.length == 5) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]];
        else if (parts.length == 6) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]];
        else if (parts.length == 7) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]];
        else if (parts.length == 8) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]][parts[7]];
        else if (parts.length == 9) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]][parts[7]][parts[8]];
        else if (parts.length == 10) opObj = window[parts[0]][parts[1]][parts[2]][parts[3]][parts[4]][parts[5]][parts[6]][parts[7]][parts[8]][parts[9]];
        return opObj;
    }
    catch (e)
    {
        return null;
    }
};



Patch.replaceOpIds = function (json, options)
{
    const opids = {};
    for (const i in json.ops)
    {
        opids[json.ops[i].id] = json.ops[i];
    }

    for (const j in json.ops)
    {
        for (const k in json.ops[j].portsOut)
        {
            const links = json.ops[j].portsOut[k].links;
            if (links)
            {
                let l = links.length;

                while (l--)
                {
                    if (links[l] && (!opids[links[l].objIn] || !opids[links[l].objOut]))
                    {
                        if (!options.doNotUnlinkLostLinks)
                        {
                            links.splice(l, 1);
                        }
                        else
                        {
                            if (options.fixLostLinks)
                            {
                                // console.log("lost link...?", links[l]);
                                const op = gui.corePatch().getOpById(links[l].objIn);
                                if (!op) console.log("op not found!");
                                else
                                {
                                    const outerOp = gui.patchView.getSubPatchOuterOp(op.uiAttribs.subPatch);
                                    if (outerOp)
                                    {
                                        op.storage = op.storage || {};
                                        op.storage.ref = op.storage.ref || CABLES.shortId();
                                        links[l].refOp = op.storage.ref;
                                        links[l].subOpRef = outerOp.storage.ref;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }



    for (const i in json.ops)
    {
        const op = json.ops[i];
        const oldId = op.id;
        let newId = CABLES.shortId();

        if (options.prefixHash) newId = prefixedHash(options.prefixHash + oldId);

        else if (options.prefixId) newId = options.prefixId + oldId;
        else if (options.refAsId) // when saving json
        {
            if (op.storage && op.storage.ref)
            {
                newId = op.storage.ref;
                delete op.storage.ref;
            }
            else
            {
                op.storage = op.storage || {};
                op.storage.ref = newId = CABLES.shortId();
            }
        }

        const newID = op.id = newId;

        if (options.oldIdAsRef) // when loading json
        {
            op.storage = op.storage || {};
            op.storage.ref = oldId;
        }

        for (const j in json.ops)
        {
            if (json.ops[j].portsIn)
                for (const k in json.ops[j].portsIn)
                {
                    if (json.ops[j].portsIn[k].links)
                    {
                        let l = json.ops[j].portsIn[k].links.length;

                        while (l--) if (json.ops[j].portsIn[k].links[l] === null) json.ops[j].portsIn[k].links.splice(l, 1);

                        for (l in json.ops[j].portsIn[k].links)
                        {
                            if (json.ops[j].portsIn[k].links[l].objIn === oldId) json.ops[j].portsIn[k].links[l].objIn = newID;
                            if (json.ops[j].portsIn[k].links[l].objOut === oldId) json.ops[j].portsIn[k].links[l].objOut = newID;
                        }
                    }
                }

            if (json.ops[j].portsOut)
                for (const k in json.ops[j].portsOut)
                {
                    if (json.ops[j].portsOut[k].links)
                    {
                        let l = json.ops[j].portsOut[k].links.length;

                        while (l--) if (json.ops[j].portsOut[k].links[l] === null) json.ops[j].portsOut[k].links.splice(l, 1);

                        for (l in json.ops[j].portsOut[k].links)
                        {
                            if (json.ops[j].portsOut[k].links[l].objIn === oldId) json.ops[j].portsOut[k].links[l].objIn = newID;
                            if (json.ops[j].portsOut[k].links[l].objOut === oldId) json.ops[j].portsOut[k].links[l].objOut = newID;
                        }
                    }
                }
        }
    }

    // set correct subpatch
    const subpatchIds = [];
    const fixedSubPatches = [];

    for (let i = 0; i < json.ops.length; i++)
    {
        // if (CABLES.Op.isSubPatchOpName(json.ops[i].objName))
        if (json.ops[i].storage && json.ops[i].storage.subPatchVer)
        {
            for (const k in json.ops[i].portsIn)
            {
                if (json.ops[i].portsIn[k].name === "patchId")
                {
                    let newId = shortId();

                    if (options.prefixHash) newId = prefixedHash(options.prefixHash + json.ops[i].portsIn[k].value);

                    const oldSubPatchId = json.ops[i].portsIn[k].value;
                    const newSubPatchId = json.ops[i].portsIn[k].value = newId;

                    subpatchIds.push(newSubPatchId);

                    for (let j = 0; j < json.ops.length; j++)
                    {
                        // op has no uiAttribs in export, we don't care about subpatches in export though
                        if (json.ops[j].uiAttribs)
                        {
                            if (json.ops[j].uiAttribs.subPatch === oldSubPatchId)
                            {
                                json.ops[j].uiAttribs.subPatch = newSubPatchId;
                                fixedSubPatches.push(json.ops[j].id);
                            }
                        }
                    }
                }
            }
        }
    }

    for (const kk in json.ops)
    {
        let found = false;
        for (let j = 0; j < fixedSubPatches.length; j++)
        {
            if (json.ops[kk].id === fixedSubPatches[j])
            {
                found = true;
                break;
            }
        }
        // op has no uiAttribs in export, we don't care about subpatches in export though
        if (!found && json.ops[kk].uiAttribs && options.parentSubPatchId != null)
            json.ops[kk].uiAttribs.subPatch = options.parentSubPatchId;
    }

    return json;
};
/**
 * remove an eventlistener
 * @instance
 * @function addEventListener
 * @param {String} name of event
 * @param {function} callback
 */

/**
 * remove an eventlistener
 * @instance
 * @function removeEventListener
 * @param {String} name of event
 * @param {function} callback
 */

/**
 * op added to patch event
 * @event onOpAdd
 *
 * @memberof Patch
 * @type {Object}
 * @property {Op} op new op
 */

/**
 * op deleted from patch
 * @event onOpDelete
 * @memberof Patch
 * @type {Object}
 * @property {Op} op that will be deleted
 */

/**
 * link event - two ports will be linked
 * @event onLink
 * @memberof Patch
 * @type {Object}
 * @property {Port} port1
 * @property {Port} port2
 */

/**
 * unlink event - a link was deleted
 * @event onUnLink
 * @memberof Patch
 * @type {Object}
 */

/**
 * variables has been changed / a variable has been added to the patch
 * @event variablesChanged
 * @memberof Patch
 * @type {Object}
 * @property {Port} port1
 * @property {Port} port2
 */

/**
 * configuration object for loading a patch
 * @typedef {Object} PatchConfig
 * @hideconstructor
 * @property {String} [prefixAssetPath=''] prefix for path to assets
 * @property {String} [assetPath=''] path to assets
 * @property {String} [jsPath=''] path to javascript files
 * @property {String} [glCanvasId='glcanvas'] dom element id of canvas element
 * @property {Function} [onError=null] called when an error occurs
 * @property {Function} [onFinishedLoading=null] called when patch finished loading all assets
 * @property {Function} [onFirstFrameRendered=null] called when patch rendered it's first frame
 * @property {Boolean} [glCanvasResizeToWindow=false] resize canvas automatically to window size
 * @property {Boolean} [doRequestAnimation=true] do requestAnimationFrame set to false if you want to trigger exec() from outside (only do if you know what you are doing)
 * @property {Boolean} [clearCanvasColor=true] clear canvas in transparent color every frame
 * @property {Boolean} [clearCanvasDepth=true] clear depth every frame
 * @property {Boolean} [glValidateShader=true] enable/disable validation of shaders *
 * @property {Boolean} [silent=false]
 * @property {Number} [fpsLimit=0] 0 for maximum possible frames per second
 * @property {String} [glslPrecision='mediump'] default precision for glsl shader
 *
 */

/* harmony default export */ const core_patch = (Patch);

;// CONCATENATED MODULE: ./src/core/embedding.js



const EMBED = {};

/**
 * add patch into html element (will create canvas and set size to fill containerElement)
 * @name CABLES.EMBED#addPatch
 * @param {object|string} _element containerElement dom element or id of element
 * @param {object} options patch options
 * @function
 */
EMBED.addPatch = function (_element, options)
{
    let el = _element;
    let id = generateUUID();
    if (typeof _element == "string")
    {
        id = _element;
        el = document.getElementById(id);

        if (!el)
        {
            console.error(id + " Polyshape Container Element not found!");
            return;
        }
    }

    const canvEl = document.createElement("canvas");
    canvEl.id = "glcanvas_" + id;
    canvEl.width = el.clientWidth;
    canvEl.height = el.clientHeight;

    window.addEventListener(
        "resize",
        function ()
        {
            this.setAttribute("width", el.clientWidth);
            this.height = el.clientHeight;
        }.bind(canvEl),
    );

    el.appendChild(canvEl);

    options = options || {};
    options.glCanvasId = canvEl.id;

    if (!options.onError)
    {
        options.onError = function (err)
        {
            console.error(err);
        };
    }

    CABLES.patch = new core_patch(options);
    return canvEl;
};



;// CONCATENATED MODULE: ./src/core/webaudio.js
/** @namespace WEBAUDIO */



const WEBAUDIO = {};

WEBAUDIO.toneJsInitialized = false;

/*
 * External JSDoc definitions
 */

/**
 * Part of the Web Audio API, the AudioBuffer interface represents a short audio asset residing in memory.
 * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/AudioBuffer}
 */

/**
 * Part of the Web Audio API, the AudioNode interface is a generic interface for representing an audio processing module.
 * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/AudioNode}
 */

/**
 * The AudioContext interface represents an audio-processing graph built from audio modules linked together
 * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/AudioContext}
 */

/**
 * Checks if a global audio context has been created and creates
 * it if necessary. This audio context can be used for native Web Audio as well as Tone.js ops.
 * Associates the audio context with Tone.js if it is being used
 * @param {CABLES.Op} op - The operator which needs the Audio Context
 */
WEBAUDIO.createAudioContext = function (op)
{
    window.AudioContext = window.AudioContext || window.webkitAudioContext;
    if (window.AudioContext)
    {
        if (!window.audioContext)
        {
            window.audioContext = new AudioContext();
        }
        // check if tone.js lib is being used
        if (window.Tone && !WEBAUDIO.toneJsInitialized)
        {
            // set current audio context in tone.js
            Tone.setContext(window.audioContext);
            WEBAUDIO.toneJsInitialized = true;
        }
    }
    else
    {
        if (op.patch.config.onError)op.logError("NO_WEBAUDIO", "Web Audio is not supported in this browser.");
        return;
    }
    return window.audioContext;
};

/**
 * Returns the audio context.
 * Before `createAudioContext` must have been called at least once.
 * It most cases you should use `createAudioContext`, which just returns the audio context
 * when it has been created already.
 */
WEBAUDIO.getAudioContext = function ()
{
    return window.audioContext;
};

/**
 * Creates an audio in port for the op with name `portName`
 * When disconnected it will disconnect the previous connected audio node
 * from the op's audio node.
 * @param {CABLES.Op} op - The operator to create the audio port in
 * @param {string} portName - The name of the port
 * @param {AudioNode} audioNode - The audionode incoming connections should connect to
 * @param {number} [inputChannelIndex=0] - If the audio node has multiple inputs, this is the index of the input channel to connect to
 * @returns {CABLES.Port|undefined} - The newly created audio in port or `undefined` if there was an error
 */
WEBAUDIO.createAudioInPort = function (op, portName, audioNode, inputChannelIndex)
{
    if (!op || !portName || !audioNode)
    {
        const msg = "ERROR: createAudioInPort needs three parameters, op, portName and audioNode";
        op.log(msg);
        throw new Error(msg);
        // return;
    }
    if (!inputChannelIndex)
    {
        inputChannelIndex = 0;
    }
    op.webAudio = op.webAudio || {};
    op.webAudio.audioInPorts = op.webAudio.audioInPorts || [];
    const port = op.inObject(portName);
    port.webAudio = {};
    port.webAudio.previousAudioInNode = null;
    port.webAudio.audioNode = audioNode;

    op.webAudio.audioInPorts[portName] = port;

    port.onChange = function ()
    {
        const audioInNode = port.get();
        // when port disconnected, disconnect audio nodes
        if (!audioInNode)
        {
            if (port.webAudio.previousAudioInNode)
            {
                try
                {
                    if (port.webAudio.previousAudioInNode.disconnect) port.webAudio.previousAudioInNode.disconnect(port.webAudio.audioNode, 0, inputChannelIndex);
                    op.setUiError("audioCtx", null);
                }
                catch (e)
                {
                    try
                    {
                        port.webAudio.previousAudioInNode.disconnect(port.webAudio.audioNode);
                    }
                    catch (er)
                    {
                        op.log(
                            "Disconnecting audio node with in/out port index, as well as without in/out-port-index did not work ",
                            e,
                        );
                        if (e.printStackTrace)
                        {
                            e.printStackTrace();
                        }
                        throw e;
                    }
                }
            }
        }
        else
        {
            try
            {
                if (audioInNode.connect)
                {
                    audioInNode.connect(port.webAudio.audioNode, 0, inputChannelIndex);
                    op.setUiError("audioCtx", null);
                }
                else op.setUiError("audioCtx", "The passed input is not an audio context. Please make sure you connect an audio context to the input.", 2);
            }
            catch (e)
            {
                op.log("Error: Failed to connect web audio node!", e);
                op.log("port.webAudio.audioNode", port.webAudio.audioNode);
                op.log("audioInNode: ", audioInNode);
                op.log("inputChannelIndex:", inputChannelIndex);
                op.log("audioInNode.connect: ", audioInNode.connect);
                throw e;
            }
        }
        port.webAudio.previousAudioInNode = audioInNode;
    };
    // TODO: Maybe add subtype to audio-node-object?
    return port;
};

/**
 * Sometimes it is necessary to replace a node of a port, if so all
 * connections to this node must be disconnected and connections to the new
 * node must be made.
 * Can be used for both Audio ports as well as AudioParam ports
 * if used with an AudioParam pass e.g. `synth.frequency` as newNode
 * @param {CABLES.Port} port - The port where the audio node needs to be replaced
 * @param oldNode
 * @param newNode
 */
WEBAUDIO.replaceNodeInPort = function (port, oldNode, newNode)
{
    const connectedNode = port.webAudio.previousAudioInNode;
    // check if connected
    if (connectedNode && connectedNode.disconnect)
    {
        try
        {
            connectedNode.disconnect(oldNode);
        }
        catch (e)
        {
            if (e.printStackTrace)
            {
                e.printStackTrace();
            }
            throw new Error("replaceNodeInPort: Could not disconnect old audio node. " + e.name + " " + e.message);
        }
        port.webAudio.audioNode = newNode;
        try
        {
            connectedNode.connect(newNode);
        }
        catch (e)
        {
            if (e.printStackTrace)
            {
                e.printStackTrace();
            }
            throw new Error("replaceNodeInPort: Could not connect to new node. " + e.name + " " + e.message);
        }
    }
};

/**
 * Creates an audio out port which takes care of (dis-)connecting on it’s own
 * @param {CABLES.op} op - The op to create an audio out port for
 * @param {string} portName - The name of the port to be created
 * @param {AudioNode} audioNode - The audio node to link to the port
 * @returns {(CABLES.Port|undefined)} - The newly created audio out port or `undefined` if there was an error
 */
WEBAUDIO.createAudioOutPort = function (op, portName, audioNode)
{
    if (!op || !portName || !audioNode)
    {
        const msg = "ERROR: createAudioOutPort needs three parameters, op, portName and audioNode";
        op.log(msg);
        throw new Error(msg);
    }

    const port = op.outObject(portName);
    // TODO: Maybe add subtype to audio-node-object?
    port.set(audioNode);
    return port;
};

/**
 * Creates an audio param in port for the op with name portName.
 * The port accepts other audio nodes as signals as well as values (numbers)
 * When the port is disconnected it will disconnect the previous connected audio node
 * from the op's audio node and restore the number value set before.
 * @param {CABLES.Op} op - The operator to create an audio param input port for
 * @param {string} portName - The name of the port to create
 * @param audioNode
 * @param options
 * @param defaultValue
 * @returns {(CABLES.Port|undefined)} - The newly created port, which takes care of (dis-)connecting on its own, or `undefined` if there was an error
 */
WEBAUDIO.createAudioParamInPort = function (op, portName, audioNode, options, defaultValue)
{
    if (!op || !portName || !audioNode)
    {
        op.log("ERROR: createAudioParamInPort needs three parameters, op, portName and audioNode");
        if (op && op.name) op.log("opname: ", op.name);
        op.log("portName", portName);
        op.log("audioNode: ", audioNode);
        return;
    }
    op.webAudio = op.webAudio || {};
    op.webAudio.audioInPorts = op.webAudio.audioInPorts || [];
    // var port = op.inObject(portName);
    const port = op.inDynamic(
        portName,
        [CONSTANTS.OP.OP_PORT_TYPE_VALUE, CONSTANTS.OP.OP_PORT_TYPE_OBJECT],
        options,
        defaultValue,
    );
    port.webAudio = {};
    port.webAudio.previousAudioInNode = null;
    port.webAudio.audioNode = audioNode;

    op.webAudio.audioInPorts[portName] = port;

    // port.onLinkChanged = function() {
    //   op.log("onLinkChanged");
    //   if(port.isLinked()) {
    //
    //       if(port.links[0].portOut.type === CABLES.CONSTANTS.OP.OP_PORT_TYPE_) { // value
    //
    //       } else if(port.links[0].portOut.type === CABLES.CONSTANTS.OP.OP_PORT_TYPE_OBJECT) { // object
    //
    //       }
    //   } else { // unlinked
    //
    //   }
    // };

    port.onChange = function ()
    {
        const audioInNode = port.get();
        const node = port.webAudio.audioNode;
        const audioCtx = WEBAUDIO.getAudioContext();

        if (audioInNode != undefined)
        {
            if (typeof audioInNode === "object" && audioInNode.connect)
            {
                try
                {
                    audioInNode.connect(node);
                }
                catch (e)
                {
                    op.log("Could not connect audio node: ", e);
                    if (e.printStackTrace)
                    {
                        e.printStackTrace();
                    }
                    throw e;
                }
                port.webAudio.previousAudioInNode = audioInNode;
            }
            else
            {
                // tone.js audio param
                if (node._param && node._param.minValue && node._param.maxValue)
                {
                    if (audioInNode >= node._param.minValue && audioInNode <= node._param.maxValue)
                    {
                        try
                        {
                            if (node.setValueAtTime)
                            {
                                node.setValueAtTime(audioInNode, audioCtx.currentTime);
                            }
                            else
                            {
                                node.value = audioInNode;
                            }
                        }
                        catch (e)
                        {
                            op.log("Possible AudioParam problem with tone.js op: ", e);
                            if (e.printStackTrace)
                            {
                                e.printStackTrace();
                            }
                            throw e;
                        }
                    }
                    else
                    {
                        op.log("Warning: The value for an audio parameter is out of range!");
                    }
                } // native Web Audio param
                else if (node.minValue && node.maxValue)
                {
                    if (audioInNode >= node.minValue && audioInNode <= node.maxValue)
                    {
                        try
                        {
                            if (node.setValueAtTime)
                            {
                                node.setValueAtTime(audioInNode, audioCtx.currentTime);
                            }
                            else
                            {
                                node.value = audioInNode;
                            }
                        }
                        catch (e)
                        {
                            op.log(
                                "AudioParam has minValue / maxValue defined, and value is in range, but setting the value failed! ",
                                e,
                            );
                            if (e.printStackTrace)
                            {
                                e.printStackTrace();
                            }
                            throw e;
                        }
                    }
                    else
                    {
                        op.log("Warning: The value for an audio parameter is out of range!");
                    }
                } // no min-max values, try anyway
                else
                {
                    try
                    {
                        if (node.setValueAtTime)
                        {
                            node.setValueAtTime(audioInNode, audioCtx.currentTime);
                        }
                        else
                        {
                            node.value = audioInNode;
                        }
                    }
                    catch (e)
                    {
                        op.log("Possible AudioParam problem (without minValue / maxValue): ", e);
                        if (e.printStackTrace)
                        {
                            e.printStackTrace();
                        }
                        throw e;
                    }
                }

                if (port.webAudio.previousAudioInNode && port.webAudio.previousAudioInNode.disconnect)
                {
                    try
                    {
                        port.webAudio.previousAudioInNode.disconnect(node);
                    }
                    catch (e)
                    {
                        op.log("Could not disconnect previous audio node: ", e);
                        throw e;
                    }
                    port.webAudio.previousAudioInNode = undefined;
                }
            }
        }
        else
        {
            // disconnected
            if (port.webAudio.previousAudioInNode)
            {
            }
        }
    };
    return port;
};


/**
 * Loads an audio file and updates the loading indicators when cables is run in the editor.
 * @param {CABLES.Patch} patch - The cables patch, when called from inside an op this is `op.patch`
 * @param {string} url - The url of the audio file to load
 * @param {function} onFinished - The callback to be called when the loading is finished, passes the AudioBuffer
 * @param {function} onError - The callback when there was an error loading the file, the rror message is passed
 * @param loadingTask
 * @see {@link https://developer.mozilla.org/de/docs/Web/API/AudioContext/decodeAudioData}
 */
WEBAUDIO.loadAudioFile = function (patch, url, onFinished, onError, loadingTask)
{
    const audioContext = WEBAUDIO.createAudioContext();

    if (!audioContext) onError(new Error("No Audiocontext"));

    let loadingId = null;
    if (loadingTask || loadingTask === undefined)
    {
        loadingId = patch.loading.start("audio", url);
        if (patch.isEditorMode()) gui.jobs().start({ "id": "loadaudio" + loadingId, "title": " loading audio (" + url + ")" });
    }
    const request = new XMLHttpRequest();

    if (!url) return;

    request.open("GET", url, true);
    request.responseType = "arraybuffer";

    request.onload = function ()
    {
        patch.loading.finished(loadingId);
        if (patch.isEditorMode()) gui.jobs().finish("loadaudio" + loadingId);

        audioContext.decodeAudioData(request.response, onFinished, onError).catch((e) =>
        {
            onError(e);
        });
    };
    request.send();
};

/**
 * Checks if the passed time is a valid time to be used in any of the Tone.js ops.
 * @param {(string|number)} t - The time to check
 * @returns {boolean} - True if time is valid, false if not
 */
WEBAUDIO.isValidToneTime = function (t)
{
    try
    {
        const time = new Tone.Time(t);
    }
    catch (e)
    {
        return false;
    }
    return true;
};

/**
 * Checks if the passed note is a valid note to be used with Tone.js
 * @param {string} note - The note to be checked, e.g. `"C4"`
 * @returns {boolean} - True if the note is a valid note, false otherwise
 */
WEBAUDIO.isValidToneNote = function (note)
{
    try
    {
        Tone.Frequency(note);
    }
    catch (e)
    {
        return false;
    }
    return true;
};



;// CONCATENATED MODULE: ./src/core/sessionvar.js
// todo: old... remove this from ops...

/**
 * todo: old... remove this from ops...
 *
 * @class
 */
const Variable = function ()
{
    let value = null;
    const changedCallbacks = [];

    this.onChanged = function (f)
    {
        changedCallbacks.push(f);
    };

    this.getValue = function ()
    {
        return value;
    };

    this.setValue = function (v)
    {
        value = v;
        this.emitChanged();
    };

    this.emitChanged = function ()
    {
        for (let i = 0; i < changedCallbacks.length; i++)
        {
            changedCallbacks[i]();
        }
    };
};



;// CONCATENATED MODULE: ./src/core/cgp/cgp_uniform.js



class cgp_uniform_Uniform extends cg_uniform
{
    constructor(__shader, __type, __name, _value, _port2, _port3, _port4, _structUniformName, _structName, _propertyName)
    {
        super(__shader, __type, __name, _value, _port2, _port3, _port4, _structUniformName, _structName, _propertyName);
        this._cgp = __shader._cgp;

        if (!_value)
        {
            // if (this.getType() == "m4") this._value = mat4.create();
            if (this.getType() == "t") this._value = this._cgp.getEmptyTexture();
            // else if (this.getType() == "2f") this._value = [0, 0];
            // else if (this.getType() == "4f") this._value = [0, 1, 0, 1];
            // else if (this.getType() == "3f") this._value = [0, 1, 0];
        }

        this.gpuBuffer = null;
    }


    updateValueF() { }

    updateValueArrayF() {}

    setValueArrayF(v)
    {
        this.needsUpdate = true;
        this._value = v;
    }

    setValueF(v)
    {
        this.needsUpdate = true;
        this._value = v;
    }

    updateValue2F() { }

    setValue2F(v)
    {
        this.needsUpdate = true;
        this._value = v;
    }

    updateValue3F() { }

    setValue3F(v)
    {
        this.needsUpdate = true;
        this._value = v;
    }

    updateValue4F() { }

    setValue4F(v)
    {
        if (v[0] == undefined)
        {
            this._log.stack("uniform value undefined");
            console.error("uniform value undefined");
        }
        this.needsUpdate = true;
        this._value = v;
    }

    setValueT(v)
    {
        if (this._value != v)
            this._shader.needsPipelineUpdate = "texture changed"; // todo really needed ? change binding instead?

        this.needsUpdate = true;
        this._value = v;
    }

    updateValueM4(v) {}

    setValueM4(v)
    {
        this.needsUpdate = true;
        this._value = v;
    }

    setValueAny(v)
    {
        this.needsUpdate = true;
        this._value = v;
    }

    updateValueAny() {}

    updateValueT() {}


    setGpuBuffer(b)
    {
        this.gpuBuffer = b;
    }

    copyToBuffer(buff, pos = 0)
    {
        if (this._type == "f")
        {
            buff[pos] = this._value;
        }
        else if (this._type == "t")
        {
        }
        else if (this._type == "4f")
        {
            buff[pos] = this._value[0];
            buff[pos + 1] = this._value[1];
            buff[pos + 2] = this._value[2];
            buff[pos + 3] = this._value[3];
        }
        else if (this._type == "f[]")
        {
            for (let i = 0; i < this._value.length; i++)
                buff[pos + i] = this._value[i];
        }
        else if (this._type == "m4")
        {
            for (let i = 0; i < 16; i++)
                buff[pos + i] = this._value[i];
        }
        else
        {
            this._log.warn("uniform copy to buffer unknown", this._type);
        }
    }

    getWgslTypeStr()
    {
        if (this._type == "m4") return "mat4x4f";
        if (this._type == "4f") return "vec4f";
        if (this._type == "3f") return "vec3f";
        if (this._type == "2f") return "vec2f";
        if (this._type == "f") return "float";
        if (this._type == "f[]") return "array<vec4f>";
        if (this._type == "i") return "int";
        if (this._type == "sampler") return "sampler";
        if (this._type == "t") return "texture_2d<f32>";
        this._log.warn("unknown type getWgslTypeStr", this._type);
        return "???";
    }

    getSizeBytes()
    {
        const bytesPerFloat = 4;
        const bytesPerInt = 4;
        if (this._type == "t") return 4;
        if (this._type == "sampler") return 4;
        if (this._type == "f") return 1 * bytesPerFloat;
        if (this._type == "2f") return 2 * bytesPerFloat;
        if (this._type == "3f") return 3 * bytesPerFloat;
        if (this._type == "4f") return 4 * bytesPerFloat;
        if (this._type == "f[]") return this._value.length * bytesPerFloat;

        if (this._type == "m4") return 4 * 4 * bytesPerFloat;

        if (this._type == "i") return 1 * bytesPerInt;
        if (this._type == "2i") return 2 * bytesPerInt;

        this._log.warn("unknown type getSizeBytes", this._type);
        return 4;
    }

    copy(newShader)
    {
        const uni = new cgp_uniform_Uniform(newShader, this._type, this._name, this._value, this._port2, this._port3, this._port4, this._structUniformName, this._structName, this._propertyName);
        uni.shaderType = this.shaderType;

        console.log(this._name, this._value, uni._value);


        return uni;
    }
}

;// CONCATENATED MODULE: ./src/core/cg/preproc.js
function preproc(str, vars)
{
    const lines = str.split("\n");
    const outLines = [];
    let stack = [];

    for (let i = 0; i < lines.length; i++)
    {
        let line = lines[i].trim();
        let parts = line.split(" ");

        if (line.startsWith("#ifdef "))
        {
            const s = vars[parts[1]];
            stack.push({ "state": s });
            continue;
        }
        if (line.startsWith("#ifndef "))
        {
            const s = vars[parts[1]];
            stack.push({ "state": !s });
            continue;
        }
        if (line.startsWith("#endif"))
        {
            stack.pop();
            continue;
        }
        const state = stack[stack.length - 1];

        if (line.startsWith("#else"))
        {
            state.state = !state.state;
            continue;
        }

        if (!state || state.state)
        {
            outLines.push(lines[i]);
        }
    }

    return outLines.join("\n");
}

;// CONCATENATED MODULE: ./src/core/cgp/cgp_gpubuffer.js


class GPUBuffer extends EventTarget
{
    constructor(cgp, name, data = null, options = {})
    {
        super();

        this.id = CABLES.shortId();

        this._name = name;
        this.floatArr = null;
        this._gpuBuffer = null;

        this.setData([0, 0, 0, 0]);
        this.needsUpdate = true;
        this._length = 0;

        if (options.buffCfg)
        {
            this._buffCfg = options.buffCfg;
        }

        if (data)
            this.setData(data);

        if (options.length) this.setLength(options.length);

        this.updateGpuBuffer(cgp);
    }

    setData(d)
    {
        // console.log((new Error()).stack);

        this.floatArr = new Float32Array(d);
        this.setLength(this.floatArr.length);

        // console.log(this.name, this.floatArr);
        this.needsUpdate = true;
    }

    setLength(s)
    {
        this._length = s;
        if (!this.floatArr || s != this.floatArr.length)
        {
            this.floatArr = new Float32Array(this._length);
            this.needsUpdate = true;
        }
    }

    updateGpuBuffer(cgp)
    {
        if (cgp) this._cgp = cgp;
        if (!this._cgp || !this._cgp.device)
        {
            console.log("no cgp...", this._name, this._cgp);
            return;
        }

        this._cgp.pushErrorScope("updateGpuBuffer");
        if (!this._gpuBuffer)
        {
            this._buffCfg = this._buffCfg || {};
            this._buffCfg.label = "gpuBuffer-" + this._name;
            if (!this._buffCfg.hasOwnProperty("size") && this.floatArr) this._buffCfg.size = this.floatArr.length * 4;
            this._buffCfg.usage = this._buffCfg.usage || (GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC);

            this._gpuBuffer = this._cgp.device.createBuffer(this._buffCfg);
        }

        // if (!isNaN(this.floatArr[0]))console.log("shit", this._name);

        if (this.floatArr)
            this._cgp.device.queue.writeBuffer(
                this._gpuBuffer,
                0,
                this.floatArr.buffer,
                this.floatArr.byteOffset,
                this.floatArr.byteLength
            );

        // this._gpuBuffer.unmap();

        this._cgp.popErrorScope();

        this.needsUpdate = false;
    }

    get name()
    {
        return this._name;
    }

    get gpuBuffer()
    {
        if (!this._gpuBuffer || this.needsUpdate) this.updateGpuBuffer();

        return this._gpuBuffer;
    }

    get length()
    {
        return this._length;
    }

    getSizeBytes()
    {
        return this.floatArr.length * 4;
    }

    dispose()
    {
        // setTimeout(() =>
        // {
        //     if (this._gpuBuffer) this._gpuBuffer.destroy();
        // }, 100);
    }
}

;// CONCATENATED MODULE: ./src/core/cgp/cgp_binding.js



class Binding
{
    /**
     * Description
     * @param {any} cgp
     * @param {any} idx
     * @param {string} name
     * @param {any} options={}
     */
    constructor(cgp, name, options = {})
    {
        if (typeof options != "object") this._log.error("binding options is not an object");
        this._index = -1;

        this._name = name;
        this._cgp = cgp;
        this._log = new Logger("cgp_binding");
        this.uniforms = [];
        this.cGpuBuffers = [];
        this._options = options;
        this.shader = null;
        this.bindingInstances = [];
        this.stageStr = options.stage;
        this.bindingType = options.bindingType || "uniform"; // "uniform", "storage", "read-only-storage",

        if (this.stageStr == "frag") this.stage = GPUShaderStage.FRAGMENT;
        else this.stage = GPUShaderStage.VERTEX;
        if (options.hasOwnProperty("index")) this._index = options.index;

        if (options.shader) this.shader = options.shader;

        this._buffer = null;
        this.isValid = true;
        this.changed = 0;

        if (this.shader)
        {
            if (this.stageStr == "frag") this.shader.bindingsFrag.push(this);
            if (this.stageStr == "vert") this.shader.bindingsVert.push(this);
            if (this._index == -1) this._index = this.shader.getNewBindingIndex();
        }

        if (this._index == -1) this._log.warn("binding could not get an index", this._name);

        this._cgp.on("deviceChange", () =>
        {
            // this.reInit();
        });
    }

    isStruct()
    {
        if (this.uniforms.length == 0) return false;

        if (this.uniforms.length == 1)
        {
            if (this.uniforms[0].type == "t" || this.uniforms[0].type == "sampler") return false;
            if (this.bindingType != "uniform") return false;
        }

        return true;
    }

    copy(newShader)
    {
        console.log("copy binding...");
        const options = {};

        for (const i in this._options)
            options[i] = this._options[i];

        options.shader = newShader;

        let binding = new Binding(this._cgp, this._name, options);

        for (let i = 0; i < this.uniforms.length; i++)
        {
            binding.addUniform(newShader.getUniform(this.uniforms[i].name)); // .copy(newShader)
        }




        return binding;
    }

    addUniform(uni)
    {
        this.uniforms.push(uni);
    }

    getSizeBytes()
    {
        let size = 0;
        for (let i = 0; i < this.uniforms.length; i++)
        {
            // console.log("UNIFORM!!!", i, this.uniforms[i], this.uniforms[i].getSizeBytes());
            // console.log("getSizeBytes", this.uniforms[i], this.uniforms[i].getSizeBytes);
            size += this.uniforms[i].getSizeBytes();
        }
        // if (this.uniforms.length == 0)console.log("NO UNIFORMS!!!");
        return size;
    }

    getShaderHeaderCode()
    {
        let str = "";

        let typeStr = "strct_" + this._name;
        let name = this._name;

        if (this.uniforms.length === 0) return "// no uniforms in bindinggroup...?\n";


        str += "// " + this.uniforms.length + " uniforms\n";

        if (this.isStruct())
        {
            str += "struct " + typeStr + "\n";
            str += "{\n";
            for (let i = 0; i < this.uniforms.length; i++)
            {
                str += "    " + this.uniforms[i].name + ": " + this.uniforms[i].getWgslTypeStr();
                if (i != this.uniforms.length - 1)str += ",";
                str += "\n";
            }
            str += "};\n";
        }
        else
        {
            typeStr = this.uniforms[0].getWgslTypeStr();
            name = this.uniforms[0].name;
        }

        str += "@group(0) ";
        str += "@binding(" + this._index + ") ";

        if (this.isStruct())
        {
            str += "var<" + this.bindingType + "> ";
        }
        else if (this.bindingType == "read-only-storage")str += "var<storage,read> ";
        else str += "var ";

        str += name + ": " + typeStr + ";\n";

        return str;
    }


    getBindingGroupLayoutEntry()
    {
        let label = "layout " + this._name + " [";
        for (let i = 0; i < this.uniforms.length; i++) label += this.uniforms[i].getName() + ",";
        label += "]";

        const o = {
            "label": label,
            "binding": this._index,
            "visibility": this.stage,
            "size": this.getSizeBytes()
        };

        if (this.uniforms.length == 1 && this.uniforms[0].getType() == "t")
        {
            o.texture = {};
        }
        else if (this.uniforms.length == 1 && this.uniforms[0].getType() == "sampler")
        {
            o.sampler = {};
        }
        else
        {
            o.buffer = {};
            o.buffer.type = this.bindingType;
        }

        return o;
    }

    getBindingGroupEntry(gpuDevice, inst)
    {
        this.isValid = false;

        const o = {
            "label": this._name + " binding",
            "binding": this._index,
            "size": this.getSizeBytes(),
            "visibility": this.stage,
        };

        if (this.uniforms.length == 0)
        {
            console.log("binding uniforms length 0");
            return;
        }

        if (this.uniforms.length == 1 && this.uniforms[0].getType() == "t")
        {
            if (this.uniforms[0].getValue() && this.uniforms[0].getValue().gpuTexture) o.resource = this.uniforms[0].getValue().gpuTexture.createView();
            else o.resource = this._cgp.getEmptyTexture().createView();// CABLES.emptyCglTexture.createView();
        }
        else if (this.uniforms.length == 1 && this.uniforms[0].getType() == "sampler")
        {
            let smplDesc = {
                "addressModeU": "mirror-repeat",
                "addressModeV": "mirror-repeat",
                "magFilter": "linear",
                "minFilter": "linear",
                "mipmapFilter": "linear",
            };

            if (this.uniforms[0].getValue()) smplDesc = this.uniforms[0].getValue().getSampler();

            const sampler = this.uniforms[0]._cgp.device.createSampler(smplDesc);
            o.resource = sampler;
        }
        else
        {
            this._createCgpuBuffer(inst);

            o.resource = {
                "buffer": this.cGpuBuffers[inst].gpuBuffer,
                "minBindingSize": this.getSizeBytes(),
                "hasDynamicOffset": 0
            };
        }

        this.isValid = true;
        this.bindingInstances[inst] = o;

        return o;
    }

    _createCgpuBuffer(inst)
    {
        let buffCfg = {
            "label": this._name,
            "size": this.getSizeBytes(),
            "usage": GPUBufferUsage.COPY_DST | GPUBufferUsage.UNIFORM,
        };

        if (this.bindingType == "read-only-storage" || this.bindingType == "storage") buffCfg.usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;

        if (this.cGpuBuffers[inst]) this.cGpuBuffers[inst].dispose();
        this.cGpuBuffers[inst] = new GPUBuffer(this._cgp, this._name + " buff", null, { "buffCfg": buffCfg });

        if (this.uniforms.length > 0 && this.uniforms[0].gpuBuffer) this.cGpuBuffers[inst] = this.uniforms[0].gpuBuffer;
    }



    update(cgp, inst)
    {
        let b = this.bindingInstances[inst];
        if (!b) b = this.getBindingGroupEntry(cgp.device, inst);

        if (this.uniforms.length == 1 && this.uniforms[0].gpuBuffer)
        {
            if (this.uniforms[0].gpuBuffer != this.cGpuBuffers[inst])
            {
                console.log("changed?!");
                this.shader._needsRecompile = true; // TODO this should actually just rebuild the bindinggroup i guess ?
            }

            if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("extern uni bind", [this.uniforms[0].getName(), this.cGpuBuffers[inst].floatArr]);
            if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();
        }
        else
        if (this.uniforms.length == 1 && this.uniforms[0].getType() == "t")
        {
            if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("uni texture");
            if (this.uniforms[0].getValue())
                if (this.uniforms[0].getValue().gpuTexture)
                {
                    this.bindingInstances[inst] = this.getBindingGroupEntry(this.uniforms[0]._cgp.device, inst);
                }
                else
                {
                    console.log("uni t has no gputexture");
                    b.resource = this._cgp.getErrorTexture().createView();
                }

            if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();
        }
        else if (this.uniforms.length == 1 && this.uniforms[0].getType() == "sampler")
        {
            if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("uni sampler");
            b.resource = this.uniforms[0].getValue();
            if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();
        }
        else
        {
            let info = ["stage " + this.stageStr + " / inst " + inst];

            // console.log("B",this.);
            // update uniform values to buffer
            const s = this.getSizeBytes() / 4;

            // if (!this.cGpuBuffers[inst])
            // this._createCgpuBuffer(inst);
            // this.cGpuBuffers[inst] = new GPUBuffer(this._cgp, "buff", null, { "buffCfg": buffCfg });

            this.cGpuBuffers[inst].setLength(s);

            let off = 0;
            for (let i = 0; i < this.uniforms.length; i++)
            {
                info.push(this.uniforms[i].getName() + " " + this.uniforms[i].getValue());
                this.uniforms[i].copyToBuffer(this.cGpuBuffers[inst].floatArr, off); // todo: check if uniform changed?

                // if (isNaN(this.cGpuBuffers[inst].floatArr[0]))
                // {
                // console.log("shitttttttt", this.cGpuBuffers[inst].floatArr[0], this.uniforms[i].getName(), this.cGpuBuffers[inst].name, this.uniforms[i]);
                // }

                off += this.uniforms[i].getSizeBytes() / 4;
            }
            if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("uni buff", info);

            // console.log("upodate", inst);

            this.cGpuBuffers[inst].updateGpuBuffer();
            // todo: only if changed...
            // cgp.device.queue.writeBuffer(
            //     b.resource.buffer,
            //     0,
            //     this._buffer.buffer,
            //     this._buffer.byteOffset,
            //     this._buffer.byteLength
            // );

            if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();
        }
    }
}

;// CONCATENATED MODULE: ./src/core/cgp/cgp_shader.js






class cgp_shader_Shader extends CgShader
{
    constructor(_cgp, _name, options = {})
    {
        super();
        if (!_cgp) throw new Error("shader constructed without cgp " + _name);
        this._log = new Logger("cgp_shader");
        this._cgp = _cgp;
        this._name = _name;
        this._uniforms = [];
        this.compute = options.compute || false;

        if (!_name) this._log.stack("no shader name given");
        this._name = _name || "unknown";
        this._compileReason = "";
        this.gpuShaderModule = null;
        this._needsRecompile = true;
        this.bindingCounter = 0;
        this.bindCountlastFrame = -1;
        this._bindingIndexCount = 0;

        this.defaultBindingVert = new Binding(_cgp, "vsUniforms", { "stage": "vert", "bindingType": "uniform", "index": this._bindingIndexCount++ });
        this.defaultBindingFrag = new Binding(_cgp, "fsUniforms", { "stage": "frag", "bindingType": "uniform", "index": this._bindingIndexCount++ });
        this.defaultBindingComp = new Binding(_cgp, "computeUniforms", { "bindingType": "uniform", "index": this._bindingIndexCount++ });
        this.bindingsFrag = [this.defaultBindingFrag];
        this.bindingsVert = [this.defaultBindingVert];
        this.bindingsComp = [this.defaultBindingComp];

        if (!this.compute)
        {
            this.uniModelMatrix = this.addUniformVert("m4", "modelMatrix");
            this.uniViewMatrix = this.addUniformVert("m4", "viewMatrix");
            this.uniProjMatrix = this.addUniformVert("m4", "projMatrix");
            this.uniNormalMatrix = this.addUniformVert("m4", "normalMatrix");
            this.uniModelViewMatrix = this.addUniformVert("m4", "modelViewMatrix");
            this._tempNormalMatrix = mat4.create();
            this._tempModelViewMatrix = mat4.create();
        }


        this._src = "";

        this._cgp.on("deviceChange", () =>
        {
            this.gpuShaderModule = null;
            this._needsRecompile = "device changed";
        });
    }

    incBindingCounter()
    {
        if (this.bindCountlastFrame != this._cgp.frame) this.bindingCounter = 0;
        else this.bindingCounter++;
        this.bindCountlastFrame = this._cgp.frame;
    }

    reInit()
    {

    }

    get isValid()
    {
        return this._isValid;
    }

    get uniforms()
    {
        return this._uniforms;
    }

    getName()
    {
        return this._name;
    }

    setWhyCompile(why)
    {
        this._compileReason = why;
    }

    getNewBindingIndex()
    {
        return ++this._bindingIndexCount;
    }


    setSource(src)
    {
        this._src = src;
        this.setWhyCompile("Source changed");
        this._needsRecompile = true;
    }

    _replaceMods(vs)
    {
        let srcHeadVert = "";
        for (let i = 0; i < this._moduleNames.length; i++)
        {
            let srcVert = "";

            for (let j = 0; j < this._modules.length; j++)
            {
                const mod = this._modules[j];
                if (mod.name == this._moduleNames[i])
                {
                    srcHeadVert += "\n//---- MOD: group:" + mod.group + ": idx:" + j + " - prfx:" + mod.prefix + " - " + mod.title + " ------\n";

                    srcVert += "\n\n//---- MOD: " + mod.title + " / " + mod.priority + " ------\n";

                    if (mod.attributes)
                        for (let k = 0; k < mod.attributes.length; k++)
                        {
                            const r = this._getAttrSrc(mod.attributes[k], false);
                            if (r.srcHeadVert)srcHeadVert += r.srcHeadVert;
                            if (r.srcVert)srcVert += r.srcVert;
                        }

                    srcHeadVert += mod.srcHead || "";
                    srcVert += mod.srcBody || "";

                    srcHeadVert += "\n//---- end mod ------\n";

                    srcVert += "\n//---- end mod ------\n";

                    srcVert = srcVert.replace(/{{mod}}/g, mod.prefix);
                    srcHeadVert = srcHeadVert.replace(/{{mod}}/g, mod.prefix);

                    srcVert = srcVert.replace(/MOD_/g, mod.prefix);
                    srcHeadVert = srcHeadVert.replace(/MOD_/g, mod.prefix);
                }
            }

            vs = vs.replace("{{" + this._moduleNames[i] + "}}", srcVert);
        }

        vs = vs.replace("{{MODULES_HEAD}}", srcHeadVert);
        return vs;
    }

    getProcessedSource()
    {
        const defs = {};
        for (let i = 0; i < this._defines.length; i++)
            defs[this._defines[i][0]] = this._defines[i][1] || true;


        let src = preproc(this._src, defs);

        let bindingsHeadVert = "";
        for (let i = 0; i < this.bindingsFrag.length; i++)
            bindingsHeadVert += this.bindingsFrag[i].getShaderHeaderCode();

        let bindingsHeadFrag = "";
        for (let i = 0; i < this.bindingsVert.length; i++)
            bindingsHeadFrag += this.bindingsVert[i].getShaderHeaderCode();



        src = bindingsHeadFrag + "\n\n////////////////\n\n" + bindingsHeadVert + "\n\n////////////////\n\n" + src;
        src = this._replaceMods(src);

        return src;
        // console.log("----------------\n", src, "\n----------------------------");
    }

    compile()
    {
        console.log("compile", this._compileReason);
        this._isValid = true;
        this._cgp.pushErrorScope("cgp_shader " + this._name);
        // console.log(this.getProcessedSource());
        this.gpuShaderModule = this._cgp.device.createShaderModule({ "code": this.getProcessedSource(), "label": this._name });
        this._cgp.popErrorScope(this.error.bind(this));
        this._needsRecompile = false;

        this.emitEvent("compiled");
    }

    error(e)
    {
        this._isValid = false;
    }

    bind()
    {
        if (!this.compute)
        {
            this.uniModelMatrix.setValue(this._cgp.mMatrix);
            this.uniViewMatrix.setValue(this._cgp.vMatrix);
            this.uniProjMatrix.setValue(this._cgp.pMatrix);

            // mat4.invert(this._tempNormalMatrix, this._cgp.mMatrix);
            // mat4.transpose(this._tempNormalMatrix, this._tempNormalMatrix);
            mat4.mul(this._tempModelViewMatrix, this._cgp.vMatrix, this._cgp.mMatrix);



            // mat4.set(this._tempNormalMatrix, this._tempModelViewMatrix);
            mat4.invert(this._tempNormalMatrix, this._tempModelViewMatrix);
            mat4.transpose(this._tempNormalMatrix, this._tempNormalMatrix);


            // cpu billboarding?
            // this._tempModelViewMatrix[0 * 4 + 0] = 1.0;
            // this._tempModelViewMatrix[0 * 4 + 1] = 0.0;
            // this._tempModelViewMatrix[0 * 4 + 2] = 0.0;

            // // #ifndef BILLBOARDING_CYLINDRIC
            // this._tempModelViewMatrix[1 * 4 + 0] = 0.0;
            // this._tempModelViewMatrix[1 * 4 + 1] = 1.0;
            // this._tempModelViewMatrix[1 * 4 + 2] = 0.0;
            // // #endif

            // this._tempModelViewMatrix[2 * 4 + 0] = 0.0;
            // this._tempModelViewMatrix[2 * 4 + 1] = 0.0;
            // this._tempModelViewMatrix[2 * 4 + 2] = 1.0;

            this.uniModelViewMatrix.setValue(this._tempModelViewMatrix);
            this.uniNormalMatrix.setValue(this._tempNormalMatrix);
        }

        if (this._needsRecompile) this.compile();
    }

    /**
     * add a uniform to the fragment shader
     * @param {String} type ['f','t', etc]
     * @param {String} name
     * @param {any} valueOrPort value or port
     * @param p2
     * @param p3
     * @param p4
     * @memberof Shader
     * @instance
     * @function addUniformFrag
     * @returns {Uniform}
     */
    addUniformFrag(type, name, valueOrPort, p2, p3, p4)
    {
        const uni = new cgp_uniform_Uniform(this, type, name, valueOrPort, p2, p3, p4);
        uni.shaderType = "frag";

        this.defaultBindingFrag.addUniform(uni);
        this.needsPipelineUpdate = "add frag uniform";

        return uni;
    }

    /**
     * add a uniform to the vertex shader
     * @param {String} type ['f','t', etc]
     * @param {String} name
     * @param {any} valueOrPort value or port
     * @param p2
     * @param p3
     * @param p4
     * @memberof Shader
     * @instance
     * @function addUniformVert
     * @returns {Uniform}
     */
    addUniformVert(type, name, valueOrPort, p2, p3, p4)
    {
        const uni = new cgp_uniform_Uniform(this, type, name, valueOrPort, p2, p3, p4);
        uni.shaderType = "vert";

        this.defaultBindingVert.addUniform(uni);
        this.needsPipelineUpdate = "add ver uniform";

        return uni;
    }

    /**
     * add a uniform to all shader programs
     * @param {String} type ['f','t', etc]
     * @param {String} name
     * @param {any} valueOrPort value or port
     * @param p2
     * @param p3
     * @param p4
     * @memberof Shader
     * @instance
     * @function addUniform
     * @returns {Uniform}
     */
    addUniform(type, name, valueOrPort, p2, p3, p4)
    {
        const uni = new cgp_uniform_Uniform(this, type, name, valueOrPort, p2, p3, p4);
        uni.shaderType = "both";
        return uni;
    }

    _addUniform(uni)
    {
        this._uniforms.push(uni);
        this.setWhyCompile("add uniform " + name);
        this._needsRecompile = true;
    }

    getUniform(name)
    {
        for (let i = 0; i < this._uniforms.length; i++)
        {
            if (this._uniforms[i].getName() == name) return this._uniforms[i];
        }
    }

    /**
     * copy current shader
     * @function copy
     * @memberof Shader
     * @instance
     * @returns newShader
     */
    copy()
    {
        const shader = new cgp_shader_Shader(this._cgp, this._name + " copy");
        shader.setSource(this._src);

        shader._modules = JSON.parse(JSON.stringify(this._modules));
        shader._defines = JSON.parse(JSON.stringify(this._defines));

        shader._modGroupCount = this._modGroupCount;
        shader._moduleNames = this._moduleNames;

        // shader.glPrimitive = this.glPrimitive;
        // shader.offScreenPass = this.offScreenPass;
        // shader._extensions = this._extensions;
        // shader.wireframe = this.wireframe;
        // shader._attributes = this._attributes;

        for (let i = 0; i < this._uniforms.length; i++) this._uniforms[i].copy(shader);

        shader.bindingsFrag = [];
        for (let i = 0; i < this.bindingsFrag.length; i++) this.bindingsFrag[i].copy(shader);
        shader.defaultBindingFrag = this.bindingsFrag[0];

        shader.bindingsVert = [];
        for (let i = 0; i < this.bindingsVert.length; i++) this.bindingsVert[i].copy(shader);
        shader.defaultBindingVert = this.bindingsVert[0];

        shader.bindingsComp = [];
        for (let i = 0; i < this.bindingsComp.length; i++) this.bindingsComp[i].copy(shader);
        shader.defaultBindingComp = this.bindingsComp[0];

        console.log("copyyyyyyyyyy", shader.bindingsVert, this.bindingsVert);

        this.setWhyCompile("copy");
        shader._needsRecompile = true;
        return shader;
    }


    /**
     * copy all uniform values from another shader
     * @function copyUniforms
     * @memberof Shader
     * @instance
     * @param origShader uniform values will be copied from this shader
     */
    copyUniformValues(origShader)
    {
        for (let i = 0; i < origShader._uniforms.length; i++)
        {
            if (!this._uniforms[i])
            {
                this._log.log("unknown uniform?!");
                continue;
            }
            this.getUniform(origShader._uniforms[i].getName()).set(origShader._uniforms[i].getValue());
        }

        // this.popTextures();
        // for (let i = 0; i < origShader._textureStackUni.length; i++)
        // {
        //     this._textureStackUni[i] = origShader._textureStackUni[i];
        //     this._textureStackTex[i] = origShader._textureStackTex[i];
        //     this._textureStackType[i] = origShader._textureStackType[i];
        //     this._textureStackTexCgl[i] = origShader._textureStackTexCgl[i];
        // }
    }
}

;// CONCATENATED MODULE: ./src/core/cgp/cgl_shader_default.wgsl
/* harmony default export */ const cgl_shader_default = ("\nstruct MyVSInput\n{\n    @location(0) position: vec3<f32>,\n    @location(1) normal: vec3<f32>,\n    @location(2) texcoord: vec2<f32>,\n};\n\nstruct MyVSOutput\n{\n    @builtin(position) position: vec4<f32>,\n    @location(0) normal: vec3<f32>,\n    @location(1) texcoord: vec2<f32>,\n};\n\n@vertex\nfn myVSMain(v: MyVSInput) -> MyVSOutput\n{\n    var vsOut: MyVSOutput;\n    var pos =vec4<f32>(v.position, 1.0);\n\n    var mvMatrix=vsUniforms.viewMatrix * vsUniforms.modelMatrix;\n    vsOut.position = vsUniforms.projMatrix * mvMatrix * pos;\n\n    vsOut.normal = v.normal;\n    vsOut.texcoord = v.texcoord;\n    return vsOut;\n}\n\n@fragment\nfn myFSMain(v: MyVSOutput) -> @location(0) vec4<f32>\n{\n    return fsUniforms.color+vec4<f32>(.5,.5,.5,1.0);\n}\n\n");
;// CONCATENATED MODULE: ./src/core/cgp/cgp_texture.js



class cgp_texture_Texture extends CgTexture
{
    constructor(_cgp, options = {})
    {
        super(options);
        if (!_cgp) throw new Error("no cgp");
        this._log = new Logger("cgp_texture");
        this._cgp = _cgp;
        // this.id = CABLES.uuid();
        this.gpuTexture = null;
        this.gpuTextureDescriptor = null;

        options = options || {};

        this.name = options.name || "unknown";

        this.samplerDesc = {
            "addressModeU": options.wrap || options.addressModeU || "clamp-to-edge",
            "addressModeV": options.wrap || options.addressModeV || "clamp-to-edge",
            "magFilter": options.magFilter || options.filter || "linear",
            "minFilter": options.minFilter || options.filter || "linear",
        };


        this._cgp.on("deviceChange", () =>
        {
            // this.reInit();
        });
    }

    /**
     * set texture data from an image/canvas object
     * @function initTexture
     * @memberof Texture
     * @instance
     * @param {Object} img image
     * @param {Number} filter
     */
    initTexture(img, filter)
    {
        this.width = img.width;
        this.height = img.height;

        const textureType = "rgba8unorm";

        this._cgp.pushErrorScope("inittexture", { "logger": this._log });

        this.gpuTextureDescriptor = {

            "size": { "width": img.width, "height": img.height },
            "format": textureType,
            "usage": GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT
        };

        this.gpuTexture = this._cgp.device.createTexture(this.gpuTextureDescriptor);
        this._cgp.device.queue.copyExternalImageToTexture({ "source": img }, { "texture": this.gpuTexture }, this.gpuTextureDescriptor.size);

        this._cgp.popErrorScope();

        return this.gpuTexture;
    }

    dispose()
    {
        console.log("todo dispose");
    }

    getInfo()
    {
        const tex = this;
        const obj = {};

        obj.name = tex.name;
        obj.size = tex.width + " x " + tex.height;

        obj.textureType = tex.textureType;

        return obj;
    }

    createView()
    {
        if (!this.gpuTexture)
        {
            console.log("no gputexture...");
            return null;
        }
        return this.gpuTexture.createView();
    }

    getSampler()
    {
        // "clamp-to-edge"
        // "repeat"
        // "mirror-repeat"

        return this.samplerDesc;
    }

    /**
     * @function initFromData
     * @memberof Texture
     * @instance
     * @description create texturem from rgb data
     * @param {Array<Number>} data rgb color array [r,g,b,a,r,g,b,a,...]
     * @param {Number} w width
     * @param {Number} h height
     * @param {Number} filter
     * @param {Number} wrap
     */
    initFromData(data, w, h, filter, wrap)
    {
        if (!w || !h) this._log.error("texture size is 0");
        this.width = w;
        this.height = h;
        this.gpuTexture = this._cgp.device.createTexture(
            {
                "size": [w, h],
                "format": "rgba8unorm",
                "usage": GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
            });

        this._cgp.device.queue.writeTexture(
            { "texture": this.gpuTexture },
            data,
            { "bytesPerRow": w * 4 },
            { "width": w, "height": h });
    }


    setWrap(v)
    {
        this.samplerDesc.addressModeU = this.samplerDesc.addressModeV = v;
    }

    setFilter(v)
    {
        this.samplerDesc.minFilter = this.samplerDesc.magFilter = v;
    }
}


/**
 * @function load
 * @static
 * @memberof Texture
 * @description load an image from an url
 * @param {Context} cgp
 * @param {String} url
 * @param {Function} onFinished
 * @param {Object} settings
 * @return {Texture}
 */
cgp_texture_Texture.load = function (cgp, url, onFinished, settings)
{
    fetch(url).then((response) =>
    {
        const texture = new cgp_texture_Texture(cgp, { "name": url });

        response.blob().then((blob) =>
        {
            createImageBitmap(blob).then((imgBitmap) =>
            {
                texture.initTexture(imgBitmap);
                if (onFinished)onFinished(texture);
                else console.log("Texture.load no onFinished callback");
            }).catch((err) =>
            {
                if (onFinished)onFinished(cgp.getErrorTexture());
            });
        });
    });
};

;// CONCATENATED MODULE: ./src/core/cgp/cgp_state.js








// https://github.com/greggman/webgpu-utils
// https://developer.chrome.com/blog/from-webgl-to-webgpu/
// https://gpuweb.github.io/gpuweb/explainer/


/**
 * cables webgpu context/state manager
 * @class
 * @namespace external:CGP
 * @hideconstructor
 */
// const Context = function (_patch)
class WebGpuContext extends CGState
{
    constructor(_patch)
    {
        super();

        this.patch = _patch;

        this.lastErrorMsg = "";

        this._log = new Logger("WebGpuContext");
        this.gApi = CG.GAPI_WEBGPU;
        this._viewport = [0, 0, 256, 256];
        this._shaderStack = [];
        this._simpleShader = null;
        this.frame = 0;
        this.catchErrors = false;

        this._stackCullFaceFacing = [];
        this._stackDepthTest = [];
        this._stackCullFace = [];
        this._stackDepthFunc = [];
        this._stackDepthWrite = [];
        this._stackErrorScope = [];
        this._stackBlend = [];
        this._stackErrorScopeLogs = [];

        this._defaultBlend = {
            "color": {
                "operation": "add",
                "srcFactor": "one",
                "dstFactor": "zero",
            },
            "alpha": {
                "operation": "add",
                "srcFactor": "one",
                "dstFactor": "zero",
            },
        };

        this.DEPTH_FUNCS = [
            "never",
            "always",
            "less",
            "less-equal",
            "greater",
            "greater-equal",
            "equal",
            "not-equal"
        ];

        this.CULL_MODES = [
            "none",
            "back",
            "front",
            "none" // both does not exist in webgpu
        ];
    }


    /// ////////////////////

    // getViewPort()
    // {
    //     return [0, 0, this.canvasWidth, this.canvasHeight];
    // }

    renderStart(cgp, identTranslate, identTranslateView)
    {
        this.frame++;
        this.pushErrorScope("cgpstate internal", "internal");
        this.pushErrorScope("cgpstate out-of-memory", "out-of-memory");

        if (!this._simpleShader)
        {
            this._simpleShader = new cgp_shader_Shader(this, "simple default shader");
            this._simpleShader.setSource(cgl_shader_default);
            this._simpleShader.addUniformFrag("4f", "color", [1, 1, 0, 1]);
        }

        this.fpsCounter.startFrame();

        this._startMatrixStacks(identTranslate, identTranslateView);
        this.setViewPort(0, 0, this.canvasWidth, this.canvasHeight);

        this.pushShader(this._simpleShader);
        this.pushDepthTest(true);
        this.pushDepthWrite(true);
        this.pushDepthFunc("less-equal");


        this.pushBlend(this._defaultBlend);

        this.emitEvent("beginFrame");
    }

    renderEnd()
    {
        this._endMatrixStacks();

        this.popShader();
        this.popDepthFunc();
        this.popDepthWrite();
        this.popDepthTest();

        this.popErrorScope();
        this.popErrorScope();

        if (this._stackErrorScope.length > 0)console.log("scope stack length invalid...");

        this.emitEvent("endFrame");
        this.fpsCounter.endFrame();
    }


    setViewPort(x, y, w, h)
    {
        this._viewport = [x, y, w, h];
    }

    /**
     * @function getViewPort
     * @memberof Context
     * @instance
     * @description get current gl viewport
     * @returns {Array} array [x,y,w,h]
     */
    getViewPort()
    {
        return this._viewPort;
    }

    createMesh(geom, glPrimitive)
    {
        return new CGP.Mesh(this, geom, glPrimitive);
    }

    /**
     * push a shader to the shader stack
     * @function pushShader
     * @memberof Context
     * @instance
     * @param {Object} shader
     * @function
    */
    pushShader(shader)
    {
        this._shaderStack.push(shader);
        // currentShader = shader;
    }

    /**
     * pop current used shader from shader stack
     * @function popShader
     * @memberof Context
     * @instance
     * @function
     */
    popShader()
    {
        if (this._shaderStack.length === 0) throw new Error("Invalid shader stack pop!");
        this._shaderStack.pop();
        // currentShader = this._shaderStack[this._shaderStack.length - 1];
    }

    getShader()
    {
        return this._shaderStack[this._shaderStack.length - 1];
        // if (currentShader) if (!this.frameStore || ((this.frameStore.renderOffscreen === true) == currentShader.offScreenPass) === true) return currentShader;
        // for (let i = this._shaderStack.length - 1; i >= 0; i--) if (this._shaderStack[i]) if (this.frameStore.renderOffscreen == this._shaderStack[i].offScreenPass) return this._shaderStack[i];
    }

    setDevice(device)
    {
        this.device = device;


        if (this._emptyTexture) this._emptyTexture = this._emptyTexture.dispose();
        if (this._defaultTexture) this._defaultTexture = this._defaultTexture.dispose();
        if (this._errorTexture) this._errorTexture = this._errorTexture.dispose();

        this.emitEvent("deviceChange");
    }

    pushErrorScope(name, options = {})
    {
        if (this.catchErrors)
        {
            this._stackErrorScope.push(name);
            this._stackErrorScopeLogs.push(options.logger || null);
            this.device.pushErrorScope(options.scope || "validation");
        }
    }

    popErrorScope(cb)
    {
        if (this.catchErrors)
        {
            const name = this._stackErrorScope.pop();
            const logger = this._stackErrorScopeLogs.pop();
            this.device.popErrorScope().then((error) =>
            {
                if (error)
                {
                    if (this.lastErrorMsg == error.message)
                    {
                        // this._log.warn("last error once more...");
                    }
                    else
                    {
                        (logger || this._log).error(error.constructor.name, "in", name);
                        (logger || this._log).error(error.message);
                    }
                    this.lastErrorMsg = error.message;

                    if (cb)cb(error);
                }
            });
        }
    }

    /**
     * push depth testing enabled state
     * @function pushDepthTest
     * @param {Boolean} b enabled
     * @memberof Context
     * @instance
     */
    pushDepthTest(b)
    {
        this._stackDepthTest.push(b);
    }

    /**
     * current state of depth testing
     * @function stateDepthTest
     * @returns {Boolean} enabled
     * @memberof Context
     * @instance
     */
    stateDepthTest()
    {
        return this._stackDepthTest[this._stackDepthTest.length - 1];
    }

    /**
     * pop depth testing state
     * @function popDepthTest
     * @memberof Context
     * @instance
     */
    popDepthTest()
    {
        this._stackDepthTest.pop();
    }

    // --------------------------------------
    // state depthwrite

    /**
     * push depth write enabled state
     * @function pushDepthWrite
     * @param {Boolean} b enabled
     * @memberof Context
     * @instance
     */
    pushDepthWrite(b)
    {
        b = b || false;
        this._stackDepthWrite.push(b);
    }

    /**
     * current state of depth writing
     * @function stateCullFace
     * @returns {Boolean} enabled
     * @memberof Context
     * @instance
     */
    stateDepthWrite()
    {
        return this._stackDepthWrite[this._stackDepthWrite.length - 1];
    }

    /**
     * pop depth writing state
     * @function popCullFace
     * @memberof Context
     * @instance
     */
    popDepthWrite()
    {
        this._stackDepthWrite.pop();
    }

    // --------------------------------------
    // state depthfunc

    /**
     * @function pushDepthFunc
     * @memberof Context
     * @instance
     * @param {string} f depth compare func
     */
    pushDepthFunc(f)
    {
        this._stackDepthFunc.push(f);
    }

    /**
     * @function stateDepthFunc
     * @memberof Context
     * @instance
     * @returns {string}
     */
    stateDepthFunc()
    {
        if (this._stackDepthFunc.length > 0) return this._stackDepthFunc[this._stackDepthFunc.length - 1];
        return false;
    }

    /**
     * pop depth compare func
     * @function popDepthFunc
     * @memberof Context
     * @instance
     */
    popDepthFunc()
    {
        this._stackDepthFunc.pop();
    }

    // --------------------------------------
    // state CullFace

    /**
     * push face culling face enabled state
     * @function pushCullFace
     * @param {Boolean} b enabled
     * @memberof Context
     * @instance
     */
    pushCullFace(b)
    {
        this._stackCullFace.push(b);
    }

    /**
     * current state of face culling
     * @function stateCullFace
     * @returns {Boolean} enabled
     * @memberof Context
     * @instance
     */
    stateCullFace()
    {
        return this._stackCullFace[this._stackCullFace.length - 1];
    }

    /**
     * pop face culling enabled state
     * @function popCullFace
     * @memberof Context
     * @instance
     */
    popCullFace()
    {
        this._stackCullFace.pop();
    }

    // --------------------------------------
    // state CullFace Facing

    /**
     * push face culling face side
     * @function pushCullFaceFacing
     * @memberof Context
     * @param b
     * @instance
     */
    pushCullFaceFacing(b)
    {
        this._stackCullFaceFacing.push(b);
    }

    /**
     * current state of face culling side
     * @function stateCullFaceFacing
     * @returns {Boolean} enabled
     * @memberof Context
     * @instance
     */
    stateCullFaceFacing()
    {
        return this._stackCullFaceFacing[this._stackCullFaceFacing.length - 1];
    }

    /**
     * pop face culling face side
     * @function popCullFaceFacing
     * @memberof Context
     * @instance
     */
    popCullFaceFacing()
    {
        this._stackCullFaceFacing.pop();
    }

    pushBlend(b)
    {
        this._stackBlend.push(b);
    }

    popBlend()
    {
        this._stackBlend.pop();
    }

    stateBlend()
    {
        return this._stackBlend[this._stackBlend.length - 1];
    }

    getEmptyTexture()
    {
        if (this._emptyTexture) return this._emptyTexture;
        const size = 8;
        this._emptyTexture = new cgp_texture_Texture(this, {});
        this._emptyTexture.initFromData(CgTexture.getDefaultTextureData("empty", size), size, size);
        return this._emptyTexture;
    }

    getErrorTexture()
    {
        // if (this._errorTexture) return this._errorTexture;
        const size = 256;
        this._errorTexture = new cgp_texture_Texture(this, {});
        this._errorTexture.initFromData(CgTexture.getDefaultTextureData("stripes", size, { "r": 1, "g": 0, "b": 0 }), size, size);
        return this._errorTexture;
    }

    getDefaultTexture()
    {
        if (this._defaultTexture) return this._defaultTexture;
        const size = 256;
        this._defaultTexture = new cgp_texture_Texture(this, {});
        this._defaultTexture.initFromData(CgTexture.getDefaultTextureData("stripes", size), size, size);
        return this._defaultTexture;
    }
}


;// CONCATENATED MODULE: ./src/core/cgp/cgp_pipeline.js



class Pipeline
{
    constructor(_cgp, name)
    {
        if (!_cgp) throw new Error("Pipeline constructed without cgp " + name);
        this._name = name;
        this._cgp = _cgp;
        this._isValid = true;
        this._log = new Logger("pipeline");

        this._pipeCfg = null;
        this._renderPipeline = null;

        this._bindGroups = [];

        this._shaderListeners = [];
        this.shaderNeedsPipelineUpdate = false;

        this._old = {};

        this.DEPTH_COMPARE_FUNCS_STRINGS = ["never", "less", "equal", "lessequal", "greater", "notequal", "greaterequal", "always"];

        this._cgp.on("deviceChange", () =>
        {
            this._renderPipeline = null;
        });
    }

    get isValid() { return this._isValid; }

    setName(name)
    {
        this._name = name;
    }

    setShaderListener(oldShader, newShader)
    {
        for (let i = 0; i < this._shaderListeners.length; i++) oldShader.off(this._shaderListeners[i]);

        this._shaderListeners.push(
            newShader.on("compiled", () =>
            {
                // console.log("pipe update shader compileeeeeee");
                // this.needsRebuildReason = "shader changed";
                this.shaderNeedsPipelineUpdate = "shader compiled";
            }));
    }


    getInfo()
    {
        // console.log(this.bindingGroupLayoutEntries);

        const arr = [
            "name: " + this._name,
            "bindgroups: " + this._bindGroups.length

        ];

        if (this.bindingGroupLayoutEntries)arr.push("layouts: " + this.bindingGroupLayoutEntries.length);

        // if (this.bindingGroupLayoutEntries)
        //     for (let i = 0; i < this.bindingGroupLayoutEntries.length; i++)
        //     {
        //         // const lines = JSON.stringify(this.bindingGroupLayoutEntries, 4, true).split(",");
        //         arr.push(...lines);
        //     }

        return arr;
    }

    setPipeline(shader, mesh)
    {
        if (!mesh || !shader)
        {
            console.log("pipeline unknown shader/mesh");
            return;
        }

        if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("setPipeline", this.getInfo());

        let needsRebuildReason = "";
        if (!this._renderPipeline) needsRebuildReason = "no renderpipeline";
        if (!this._pipeCfg)needsRebuildReason = "no pipecfg";
        if (this._old.mesh != mesh)needsRebuildReason = "no mesh";
        if (this._old.shader != shader)
        {
            this.setShaderListener(this._old.shader, shader);
            needsRebuildReason = "shader changed";
        }

        if (shader.needsPipelineUpdate)
        {
            needsRebuildReason = "mesh needs update: " + shader.needsPipelineUpdate;
            shader.needsPipelineUpdate = false;
        }
        if (mesh.needsPipelineUpdate)needsRebuildReason = "mesh needs update";
        if (this.shaderNeedsPipelineUpdate)needsRebuildReason = "shader was recompiled: " + this.shaderNeedsPipelineUpdate;

        if (this._pipeCfg)
        {
            if (this._pipeCfg.depthStencil.depthWriteEnabled != this._cgp.stateDepthWrite())
            {
                needsRebuildReason = "depth changed";
                this._pipeCfg.depthStencil.depthWriteEnabled = this._cgp.stateDepthWrite();
            }

            if (this._pipeCfg.fragment.targets[0].blend != this._cgp.stateBlend())
            {
                needsRebuildReason = "blend changed";
                this._pipeCfg.fragment.targets[0].blend = this._cgp.stateBlend();
            }

            // "fragment": {
            //     "module": shader.gpuShaderModule,
            //     "entryPoint": "myFSMain",
            //     "targets": [
            //         {
            //             "format": this._cgp.presentationFormat,
            //             "blend":
            //         },


            if (this._cgp.stateDepthTest() === false)
            {
                if (this._pipeCfg.depthStencil.depthCompare != "never")
                {
                    this._pipeCfg.depthStencil.depthCompare = "never";
                    needsRebuildReason = "depth compare changed";
                }
            }
            else
            if (this._pipeCfg.depthStencil.depthCompare != this._cgp.stateDepthFunc())
            {
                needsRebuildReason = "depth state ";
                this._pipeCfg.depthStencil.depthCompare = this._cgp.stateDepththis._cgp.stateDepthFunc();
            }

            // console.log(this._pipeCfg.primitive.cullMode, this._cgp.stateCullFaceFacing());
            if (this._pipeCfg.primitive.cullMode != this._cgp.stateCullFaceFacing())
            {
                needsRebuildReason = "cullmode change";
                this._pipeCfg.primitive.cullMode = this._cgp.stateCullFaceFacing();
            }
        }

        this._cgp.currentPipeDebug =
        {
            "cfg": this._pipeCfg,
            "bindingGroupEntries": this.bindingGroupEntries,
            "bindingGroupLayoutEntries": this.bindingGroupLayoutEntries
        };


        if (needsRebuildReason != "")
        {
            console.log("rebuild pipe", needsRebuildReason);
            this._cgp.pushErrorScope("createPipeline", { "logger": this._log });

            this._bindGroups = [];

            this._pipeCfg = this.getPipelineObject(shader, mesh);
            this._old.device = this._cgp.device;
            this._old.shader = shader;
            this._old.mesh = mesh;
            this._renderPipeline = this._cgp.device.createRenderPipeline(this._pipeCfg);

            this._cgp.popErrorScope();
        }


        if (this._renderPipeline && this._isValid)
        {
            this._cgp.pushErrorScope("setpipeline", { "logger": this._log });


            this._cgp.passEncoder.setPipeline(this._renderPipeline);

            if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("updateUniforms");

            shader.incBindingCounter();

            if (!this._bindGroups[shader.bindingCounter])
            {
                const bindingGroupEntries = [];

                for (let i = 0; i < shader.bindingsVert.length; i++)
                {
                    if (shader.bindingsVert[i].getSizeBytes() > 0)
                    {
                        bindingGroupEntries.push(shader.bindingsVert[i].getBindingGroupEntry(this._cgp.device, shader.bindingCounter));
                    }
                    else console.log("shader defaultBindingVert size 0");
                }
                for (let i = 0; i < shader.bindingsFrag.length; i++)
                {
                    if (shader.bindingsFrag[i].getSizeBytes() > 0)
                    {
                        bindingGroupEntries.push(shader.bindingsFrag[i].getBindingGroupEntry(this._cgp.device, shader.bindingCounter));
                    }
                    else console.log("shader defaultBindingFrag size 0");
                }

                const bg = {
                    "label": "label2",
                    "layout": this.bindGroupLayout,
                    "entries": bindingGroupEntries
                };

                this._bindGroups[shader.bindingCounter] = this._cgp.device.createBindGroup(bg);
            }

            this._bindUniforms(shader, shader.bindingCounter);

            if (this._bindGroups[shader.bindingCounter]) this._cgp.passEncoder.setBindGroup(0, this._bindGroups[shader.bindingCounter]);


            // shader.bindingCounter++;

            if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();

            this._cgp.popErrorScope();
        }
        if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();


        this.shaderNeedsPipelineUpdate = false;
    }

    getPipelineObject(shader, mesh)
    {
        this.bindingGroupLayoutEntries = [];

        for (let i = 0; i < shader.bindingsVert.length; i++)
        {
            if (shader.bindingsVert[i].getSizeBytes() > 0)
            {
                this.bindingGroupLayoutEntries.push(shader.bindingsVert[i].getBindingGroupLayoutEntry());
            }
            else console.log("shader defaultBindingVert size 0");
        }

        for (let i = 0; i < shader.bindingsFrag.length; i++)
        {
            if (shader.bindingsFrag[i].getSizeBytes() > 0)
            {
                this.bindingGroupLayoutEntries.push(shader.bindingsFrag[i].getBindingGroupLayoutEntry());
            }
            else console.log("shader defaultBindingFrag size 0");
        }
        // //////////

        this.bindGroupLayout = this._cgp.device.createBindGroupLayout(
            {
                "label": "bg layout " + this._name,
                "entries": this.bindingGroupLayoutEntries,
            });

        const pipelineLayout = this._cgp.device.createPipelineLayout({
            "label": "pipe layout " + this._name,
            "bindGroupLayouts": [this.bindGroupLayout]
        });


        let buffers = [
            // position
            {
                "arrayStride": 3 * 4, // 3 floats, 4 bytes each
                "attributes": [
                    { "shaderLocation": 0, "offset": 0, "format": "float32x3" },
                ],
            },
            // texcoords
            {
                "arrayStride": 2 * 4, // 2 floats, 4 bytes each
                "attributes": [
                    { "shaderLocation": 2, "offset": 0, "format": "float32x2", },
                ],
            },
            // normals
            {
                "arrayStride": 3 * 4, // 3 floats, 4 bytes each
                "attributes": [
                    { "shaderLocation": 1, "offset": 0, "format": "float32x3" },
                ],
            }];



        const pipeCfg = {
            // "layout": "auto",
            "label": this._name,
            "layout": pipelineLayout,
            "vertex": {
                "module": shader.gpuShaderModule,
                "entryPoint": "myVSMain",
                "buffers": buffers

            },
            "fragment": {
                "module": shader.gpuShaderModule,
                "entryPoint": "myFSMain",
                "targets": [
                    {
                        "format": this._cgp.presentationFormat,
                        "blend": this._cgp.stateBlend()
                    },
                ],
            },
            "primitive": {
                "topology": "triangle-list",
                "cullMode": this._cgp.stateCullFaceFacing(), // back/none/front

                // "point-list",
                // "line-list",
                // "line-strip",
                // "triangle-list",
                // "triangle-strip"
            },
            "depthStencil": {
                "depthWriteEnabled": this._cgp.stateDepthTest(),
                "depthCompare": this._cgp.stateDepthFunc(),
                "format": "depth24plus",
            },

        };

        return pipeCfg;
    }


    _bindUniforms(shader, inst)
    {
        // this._cgp.pushErrorScope("pipeline bind uniforms", { "logger": this._log });

        shader.bind();

        if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("bind uniforms vert", ["num:" + shader.bindingsVert.length]);
        for (let i = 0; i < shader.bindingsVert.length; i++) shader.bindingsVert[i].update(this._cgp, inst);
        if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();

        if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("bind uniforms frag", ["num:" + shader.bindingsFrag.length]);
        for (let i = 0; i < shader.bindingsFrag.length; i++) shader.bindingsFrag[i].update(this._cgp, inst);
        if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();



        // shader.defaultBindingVert.update(this._cgp);

        // this._cgp.popErrorScope((e) =>
        // {
        //     this._isValid = false;
        // });
    }
}

;// CONCATENATED MODULE: ./src/core/cgp/cgp_mesh.js



class cgp_mesh_Mesh
{
    constructor(_cgp, __geom)
    {
        this._log = new Logger("cgl_mesh");
        this._cgp = _cgp;
        this._geom = null;
        this.numIndex = 0;
        this.instances = 1;

        this._pipe = new Pipeline(this._cgp, "new mesh");
        this._numNonIndexed = 0;
        this._positionBuffer = null;
        this._bufVerticesIndizes = null;
        this._attributes = [];
        this._needsPipelineUpdate = false;

        if (__geom) this.setGeom(__geom);
    }

    _createBuffer(device, data, usage)
    {
        let bo = {
            "size": data.byteLength,
            "usage": usage,
            "mappedAtCreation": true,
        };
        // ifbo.stepMode = "instance";
        const buffer = device.createBuffer(bo);
        const dst = new data.constructor(buffer.getMappedRange());
        dst.set(data);
        buffer.unmap();
        return buffer;
    }

    /**
     * @function setGeom
     * @memberof Mesh
     * @instance
     * @description set geometry for mesh
     * @param {Geometry} geom geometry
     * @param {boolean} removeRef
     */
    setGeom(geom, removeRef)
    {
        this._needsPipelineUpdate = true;
        this._geom = geom;
        this._disposeAttributes();

        this._positionBuffer = this._createBuffer(this._cgp.device, new Float32Array(geom.vertices), GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST);

        let vi = geom.verticesIndices;
        if (!geom.isIndexed()) vi = Array.from(Array(geom.vertices.length / 3).keys());
        this._numIndices = vi.length;
        this._indicesBuffer = this._createBuffer(this._cgp.device, new Uint32Array(vi), GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST);

        if (geom.texCoords && geom.texCoords.length) this.setAttribute("texCoords", geom.texCoords, 2);
        if (geom.vertexNormals && geom.vertexNormals.length) this.setAttribute("normals", geom.vertexNormals, 3);

        this.setAttribute("normals", geom.vertexNormals, 3);
    }


    _disposeAttributes()
    {
        this._needsPipelineUpdate = true;
        for (let i = 0; i < this._attributes.length; i++)
        {
            this._attributes[i].buffer.destroy();
        }
        this._attributes.length = 0;
    }

    dispose()
    {
        this._disposeAttributes();
    }

    /**
     * @function setAttribute
     * @description update attribute
     * @memberof Mesh
     * @instance
     * @param {String} name attribute name
     * @param {Array} array data
     * @param {Number} itemSize
     * @param {Object} options
     */
    setAttribute(name, array, itemSize, options = {})
    {
        if (!array)
        {
            this._log.error("mesh addAttribute - no array given! " + name);
            throw new Error();
        }

        let instanced = false;
        if (options.instanced) instanced = options.instanced;

        const buffer = this._createBuffer(this._cgp.device, new Float32Array(array), GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST);

        const attr = {
            "buffer": buffer,
            "name": name,
            "instanced": instanced,
        };
        this._attributes.push(attr);

        return attr;
    }


    render()
    {
        if (!this._positionBuffer) return;
        if (this.instances <= 0) return;

        const shader = this._cgp.getShader();
        if (shader)shader.bind();

        if (!this._cgp.getShader() || !this._cgp.getShader().isValid)
        {
            // this.status = "shader invalid";
            return;
        }

        if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.push("mesh", ["geom " + this._geom.name, "shader " + this._cgp.getShader().getName()]);

        this._pipe.setName("mesh " + this._geom.name + " " + this._cgp.getShader().getName());
        this._pipe.setPipeline(this._cgp.getShader(), this);


        if (this._pipe.isValid)
        {
            this._cgp.passEncoder.setVertexBuffer(0, this._positionBuffer);
            for (let i = 0; i < this._attributes.length; i++)
            {
                this._cgp.passEncoder.setVertexBuffer(i + 1, this._attributes[i].buffer);
            }

            this._cgp.passEncoder.setIndexBuffer(this._indicesBuffer, "uint32");

            if (this._numNonIndexed)
                this._cgp.passEncoder.draw(this._numIndices, this.instances);
            else
                this._cgp.passEncoder.drawIndexed(this._numIndices, this.instances);
        }

        if (this._cgp.frameStore.branchProfiler) this._cgp.frameStore.branchStack.pop();

        // if (shader)shader.unbind();
    }
}

;// CONCATENATED MODULE: ./src/core/cgp/index.js










const cgp_CGP = {
    "Context": WebGpuContext,
    "Shader": cgp_shader_Shader,
    "Mesh": cgp_mesh_Mesh,
    "Pipeline": Pipeline,
    "Texture": cgp_texture_Texture,
    "Binding": Binding,
    "Uniform": cgp_uniform_Uniform,
    "MESHES": MESHES,
    "GPUBuffer": GPUBuffer
};

window.CABLES = window.CABLES || {};
window.CABLES.CGP = cgp_CGP;
window.CGP = cgp_CGP;




;// CONCATENATED MODULE: ./src/core/cgl/cgl_framebuffer.js



// todo: convert to prototyped...

/**
 * a framebuffer
 * @constructor
 * @class
 * @constructs Framebuffer
 * @param {Context} _cgl cgl
 * @param {Number} _w width
 * @param {Number} _h height
 * @param {Object} options
 */
const Framebuffer = function (_cgl, _w, _h, options)
{
    const cgl = _cgl;
    this._log = new Logger("Framebuffer");
    this.valid = true;

    let depthTextureExt = cgl.gl.DEPTH_TEXTURE;
    if (!depthTextureExt) depthTextureExt = cgl.enableExtension("WEBGL_depth_texture");
    if (!depthTextureExt) depthTextureExt = cgl.enableExtension("WEBKIT_WEBGL_depth_texture");
    if (!depthTextureExt) depthTextureExt = cgl.enableExtension("MOZ_WEBGL_depth_texture");

    if (!depthTextureExt)
    {
        this._log.error("NO_DEPTH_TEXTURE", "no depth texture support");
        return;
    }

    let width = _w || 512;
    let height = _h || 512;

    options = options || {
        "isFloatingPointTexture": false,
    };

    if (!options.hasOwnProperty("clear")) options.clear = true;
    if (!options.hasOwnProperty("filter")) options.filter = Texture.FILTER_LINEAR;

    const texture = new Texture(cgl, {
        "isFloatingPointTexture": options.isFloatingPointTexture,
        "filter": options.filter,
        "wrap": options.wrap || Texture.CLAMP_TO_EDGE
    });

    let textureDepth = null;
    if (depthTextureExt)
    {
        textureDepth = new Texture(cgl, {
            "isDepthTexture": true,
        });
    }
    this._options = options;

    const frameBuf = cgl.gl.createFramebuffer();
    const depthBuffer = cgl.gl.createRenderbuffer();

    this.getWidth = function ()
    {
        return width;
    };
    this.getHeight = function ()
    {
        return height;
    };

    /**
     * get native gl framebuffer
     * @function getGlFrameBuffer
     * @memberof Framebuffer
     * @returns {Object} framebuffer
     */
    this.getGlFrameBuffer = function ()
    {
        return frameBuf;
    };

    /**
     * get depth renderbuffer
     * @function getDepthRenderBuffer
     * @memberof Framebuffer
     * @returns {Object} renderbuffer
     */
    this.getDepthRenderBuffer = function ()
    {
        return depthBuffer;
    };

    /**
     * get color texture
     * @function getTextureColor
     * @memberof Framebuffer
     * @returns {Texture} rgba texture
     */
    this.getTextureColor = function ()
    {
        return texture;
    };

    /**
     * get depth texture
     * @function getTextureDepth
     * @memberof Framebuffer
     * @returns {Texture} depth texture
     */
    this.getTextureDepth = function ()
    {
        return textureDepth;
    };

    this.setFilter = function (f)
    {
        texture.filter = f;
        texture.setSize(width, height);
    };

    this.setSize = function (w, h)
    {
        if (w < 2) w = 2;
        if (h < 2) h = 2;

        width = Math.ceil(w);
        height = Math.ceil(h);

        cgl.profileData.profileFrameBuffercreate++;

        cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, frameBuf);
        cgl.gl.bindRenderbuffer(cgl.gl.RENDERBUFFER, depthBuffer);

        texture.setSize(width, height);
        if (textureDepth) textureDepth.setSize(width, height);

        // if(depthTextureExt) cgl.gl.renderbufferStorage(cgl.gl.RENDERBUFFER, cgl.gl.DEPTH_COMPONENT16, width,height);
        if (depthTextureExt) cgl.gl.renderbufferStorage(cgl.gl.RENDERBUFFER, cgl.gl.DEPTH_COMPONENT16, width, height);

        cgl.gl.framebufferTexture2D(cgl.gl.FRAMEBUFFER, cgl.gl.COLOR_ATTACHMENT0, cgl.gl.TEXTURE_2D, texture.tex, 0);

        if (depthTextureExt)
        {
            cgl.gl.framebufferRenderbuffer(cgl.gl.FRAMEBUFFER, cgl.gl.DEPTH_ATTACHMENT, cgl.gl.RENDERBUFFER, depthBuffer);
            cgl.gl.framebufferTexture2D(
                cgl.gl.FRAMEBUFFER,
                cgl.gl.DEPTH_ATTACHMENT, // safari needs DEPTH_ATTACHMENT NOT DEPTH_ATTACHMENT16
                // cgl.gl.DEPTH_COMPONENT16,
                cgl.gl.TEXTURE_2D,
                textureDepth.tex,
                0,
            );
        }

        if (!cgl.gl.isFramebuffer(frameBuf)) throw new Error("Invalid framebuffer");
        const status = cgl.gl.checkFramebufferStatus(cgl.gl.FRAMEBUFFER);

        switch (status)
        {
        case cgl.gl.FRAMEBUFFER_COMPLETE:
            break;
        case cgl.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
            this._log.warn("FRAMEBUFFER_INCOMPLETE_ATTACHMENT...", width, height, texture.tex, depthBuffer);
            this.valid = false;
            throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
        case cgl.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
            this._log.warn("FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
            this.valid = false;
            throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
        case cgl.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
            this._log.warn("FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
            this.valid = false;
            throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
        case cgl.gl.FRAMEBUFFER_UNSUPPORTED:
            this._log.warn("FRAMEBUFFER_UNSUPPORTED");
            this.valid = false;
            this._log.warn(width, height, options);

            throw new Error("Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED");
        case 0x8CDB:
            this._log.warn("Incomplete: FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER from ext. Or Safari/iOS undefined behaviour.");
            this.valid = false;
            break;
        default:
            this._log.warn("incomplete framebuffer", status);
            this.valid = false;
            throw new Error("Incomplete framebuffer: " + status);
        }

        cgl.gl.bindTexture(cgl.gl.TEXTURE_2D, null);
        cgl.gl.bindRenderbuffer(cgl.gl.RENDERBUFFER, null);
        cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, null);
    };

    this.renderStart = function ()
    {
        cgl.pushModelMatrix();
        cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, frameBuf);
        cgl.pushGlFrameBuffer(frameBuf);
        cgl.pushFrameBuffer(this);

        cgl.pushPMatrix();
        cgl.gl.viewport(0, 0, width, height);

        if (this._options.clear)
        {
            cgl.gl.clearColor(0, 0, 0, 0);
            cgl.gl.clear(cgl.gl.COLOR_BUFFER_BIT | cgl.gl.DEPTH_BUFFER_BIT);
        }
    };

    this.renderEnd = function ()
    {
        cgl.popPMatrix();
        cgl.gl.bindFramebuffer(cgl.gl.FRAMEBUFFER, cgl.popGlFrameBuffer());
        cgl.popFrameBuffer();

        cgl.popModelMatrix();
        cgl.resetViewPort();
    };


    this.delete = function ()
    {
        texture.delete();
        this.valid = false;
        if (textureDepth) textureDepth.delete();
        cgl.gl.deleteRenderbuffer(depthBuffer);
        cgl.gl.deleteFramebuffer(frameBuf);
    };

    this.dispose = this.delete;

    this.setSize(width, height);
};



;// CONCATENATED MODULE: ./src/core/cgl/cgl_framebuffer2.js
// * see framebuffer1






const Framebuffer2 = function (cgl, w, h, options)
{
    this._log = new Logger("cgl_framebuffer2");
    if (cgl.glVersion == 1) return this._log.error("framebuffer2 used on webgl1");
    this.Framebuffer2DrawTargetsDefault = null;
    this.Framebuffer2BlittingFramebuffer = null;
    this.Framebuffer2FinalFramebuffer = null;
    this._cgl = cgl;

    this._cgl.printError("before framebuffer2 constructor");

    this._width = 0;
    this._height = 0;
    this.valid = true;

    this._depthRenderbuffer = null;
    this._frameBuffer = null;
    this._textureFrameBuffer = null;
    this._colorRenderbuffers = [];
    this._drawTargetArray = [];
    this._disposed = false;

    if (!this.Framebuffer2BlittingFramebuffer) this.Framebuffer2BlittingFramebuffer = cgl.gl.createFramebuffer();
    if (!this.Framebuffer2FinalFramebuffer) this.Framebuffer2FinalFramebuffer = cgl.gl.createFramebuffer();

    if (!this.Framebuffer2DrawTargetsDefault) this.Framebuffer2DrawTargetsDefault = [cgl.gl.COLOR_ATTACHMENT0];

    this._options = options || {
        "isFloatingPointTexture": false,
    };

    // this._cgl.printError("fb2 before");

    this.name = this._options.name || "unknown";

    this._cgl.profileData.addHeavyEvent("framebuffer create", this.name);

    if (!this._options.hasOwnProperty("numRenderBuffers")) this._options.numRenderBuffers = 1;
    if (!this._options.hasOwnProperty("depth")) this._options.depth = true;
    if (!this._options.hasOwnProperty("clear")) this._options.clear = true;
    if (!this._options.hasOwnProperty("multisampling"))
    {
        this._options.multisampling = false;
        this._options.multisamplingSamples = 0;
    }

    if (this._options.multisamplingSamples)
    {
        if (this._cgl.glSlowRenderer) this._options.multisamplingSamples = 0;
        if (!this._cgl.gl.MAX_SAMPLES) this._options.multisamplingSamples = 0;
        else this._options.multisamplingSamples = Math.min(this._cgl.maxSamples, this._options.multisamplingSamples);
    }

    if (!this._options.hasOwnProperty("filter")) this._options.filter = Texture.FILTER_LINEAR;
    if (!this._options.hasOwnProperty("wrap")) this._options.wrap = Texture.WRAP_REPEAT;

    this._numRenderBuffers = this._options.numRenderBuffers;
    this._colorTextures = [];

    this.clearColors = [];
    for (let i = 0; i < this._numRenderBuffers; i++) this.clearColors.push([0, 0, 0, 1]);


    if (!options.pixelFormat)
    {
        if (options.isFloatingPointTexture) this._options.pixelFormat = Texture.PFORMATSTR_RGBA32F;
        else this._options.pixelFormat = Texture.PFORMATSTR_RGBA8UB;
    }

    for (let i = 0; i < this._numRenderBuffers; i++)
    {
        this._colorTextures[i] = new Texture(cgl, {
            "name": "fb2 " + this.name + " " + i,
            "isFloatingPointTexture": this._options.isFloatingPointTexture,
            "anisotropic": this._options.anisotropic || 0,
            "pixelFormat": this._options.pixelFormat,
            "filter": this._options.filter,
            "wrap": this._options.wrap,
        });
    }



    let fil = Texture.FILTER_NEAREST;
    if (this._options.shadowMap) fil = Texture.FILTER_LINEAR;

    const defaultTexSize = 512;

    if (this._options.depth)
    {
        this._textureDepth = new Texture(cgl,
            {
                "name": "fb2 depth " + this.name,
                "isDepthTexture": true,
                "filter": fil,
                "shadowMap": this._options.shadowMap || false,
                "width": w || defaultTexSize,
                "height": h || defaultTexSize,
            });
    }

    if (cgl.aborted) return;

    this.setSize(w || defaultTexSize, h || defaultTexSize);

    this._cgl.printError("framebuffer2 constructor");
};

Framebuffer2.prototype.getWidth = function ()
{
    return this._width;
};
Framebuffer2.prototype.getHeight = function ()
{
    return this._height;
};

Framebuffer2.prototype.getGlFrameBuffer = function ()
{
    return this._frameBuffer;
};

Framebuffer2.prototype.getDepthRenderBuffer = function ()
{
    return this._depthRenderbuffer;
};

Framebuffer2.prototype.getTextureColor = function ()
{
    return this._colorTextures[0];
};

Framebuffer2.prototype.getTextureColorNum = function (i)
{
    return this._colorTextures[i];
};

Framebuffer2.prototype.getTextureDepth = function ()
{
    return this._textureDepth;
};

Framebuffer2.prototype.setFilter = function (f)
{
    for (let i = 0; i < this._numRenderBuffers; i++)
    {
        this._colorTextures[i].filter = f;
        this._colorTextures[i].setSize(this._width, this._height);
    }
};

Framebuffer2.prototype.delete = Framebuffer2.prototype.dispose = function ()
{
    this._disposed = true;
    let i = 0;
    for (i = 0; i < this._numRenderBuffers; i++) this._colorTextures[i].delete();
    // this._texture.delete();
    if (this._textureDepth) this._textureDepth.delete();
    for (i = 0; i < this._numRenderBuffers; i++) this._cgl.gl.deleteRenderbuffer(this._colorRenderbuffers[i]);
    this._cgl.gl.deleteRenderbuffer(this._depthRenderbuffer);
    this._cgl.gl.deleteFramebuffer(this._frameBuffer);
    this._cgl.gl.deleteFramebuffer(this._textureFrameBuffer);
};

Framebuffer2.prototype.setSize = function (w, h)
{
    if (this._disposed) return this._log.warn("disposed framebuffer setsize...");
    this._cgl.profileData.addHeavyEvent("framebuffer resize", this.name);

    let i = 0;

    this._width = this._cgl.checkTextureSize(w);
    this._height = this._cgl.checkTextureSize(h);

    this._cgl.profileData.profileFrameBuffercreate++;

    if (this._frameBuffer)
    {
        for (i = 0; i < this._numRenderBuffers; i++) this._cgl.gl.deleteRenderbuffer(this._colorRenderbuffers[i]);
        // this._cgl.gl.deleteRenderbuffer(this._colorRenderbuffer);
        this._cgl.gl.deleteRenderbuffer(this._depthRenderbuffer);
        this._cgl.gl.deleteFramebuffer(this._frameBuffer);
        this._cgl.gl.deleteFramebuffer(this._textureFrameBuffer);
    }

    this._frameBuffer = this._cgl.gl.createFramebuffer();
    this._textureFrameBuffer = this._cgl.gl.createFramebuffer();

    const depth = this._options.depth;

    for (i = 0; i < this._numRenderBuffers; i++)
    {
        this._colorTextures[i].setSize(this._width, this._height);
    }

    for (i = 0; i < this._numRenderBuffers; i++)
    {
        const renderBuffer = this._cgl.gl.createRenderbuffer();

        // color renderbuffer

        this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuffer);
        this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, renderBuffer);

        const info = Texture.setUpGlPixelFormat(this._cgl, this._options.pixelFormat);
        let internFormat = info.glInternalFormat;

        // if (this._options.isFloatingPointTexture)
        // {
        if (CGL.Texture.isPixelFormatHalfFloat(info.pixelFormat))
        {
            if (!this._cgl.enableExtension("OES_texture_float_linear"))
            {
                this._options.filter = Texture.FILTER_NEAREST;
                this.setFilter(this._options.filter);
            }
        }
        else if (CGL.Texture.isPixelFormatFloat(info.pixelFormat))
        {
            if (!this._cgl.enableExtension("OES_texture_float_linear"))
            {
                this._log.warn("no linear pixelformat,using nearest");
                this._options.filter = Texture.FILTER_NEAREST;
                this.setFilter(this._options.filter);
            }
        }
        // else if (info.pixelFormat == Texture.PFORMATSTR_RGBA32F || info.pixelFormat == Texture.PFORMATSTR_R11FG11FB10F
        // else if (info.pixelFormat == Texture.PFORMATSTR_RGBA32F || info.pixelFormat == Texture.PFORMATSTR_R11FG11FB10F
        // else if (info.pixelFormat == Texture.PFORMATSTR_RG16F)
        // {
        //     const extcb = this._cgl.enableExtension("EXT_color_buffer_float");

        //     if (!this._cgl.enableExtension("OES_texture_float_linear"))
        //     {
        //         console.log("no linear pixelformat,switching to nearest");
        //         this._options.filter = Texture.FILTER_NEAREST;
        //         this.setFilter(this._options.filter);
        //     }
        // }
        // }

        if (this._options.multisampling && this._options.multisamplingSamples)
        {
            this._cgl.gl.renderbufferStorageMultisample(this._cgl.gl.RENDERBUFFER, this._options.multisamplingSamples, internFormat, this._width, this._height);
        }
        else
        {
            this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, internFormat, this._width, this._height);
        }



        this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0 + i, this._cgl.gl.RENDERBUFFER, renderBuffer);
        this._colorRenderbuffers[i] = renderBuffer;
    }

    // this._cgl.gl.bindFramebuffer(this._cgl.gl.DRAW_FRAMEBUFFER, this._textureFrameBuffer);
    this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._textureFrameBuffer);

    for (i = 0; i < this._numRenderBuffers; i++)
    {
        this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0 + i, this._cgl.gl.TEXTURE_2D, this._colorTextures[i].tex, 0);
    }

    if (this._options.depth)
    {
        this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.TEXTURE_2D, this._textureDepth.tex, 0);
    }

    // depth renderbuffer

    this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuffer);


    let depthType = this._cgl.gl.DEPTH_COMPONENT32F;

    if (this._cgl.glSlowRenderer) depthType = this._cgl.gl.DEPTH_COMPONENT16;
    if (depth)
    {
        this._textureDepth.setSize(this._width, this._height);
        this._depthRenderbuffer = this._cgl.gl.createRenderbuffer();

        this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, this._depthRenderbuffer);
        if (this._options.isFloatingPointTexture)
        {
            if (this._options.multisampling) this._cgl.gl.renderbufferStorageMultisample(this._cgl.gl.RENDERBUFFER, this._options.multisamplingSamples, depthType, this._width, this._height);
            else this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, depthType, this._width, this._height);
        }
        else if (this._options.multisampling)
        {
            this._cgl.gl.renderbufferStorageMultisample(this._cgl.gl.RENDERBUFFER, this._options.multisamplingSamples, depthType, this._width, this._height);
            // this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER,depthType, this._width, this._height);
        }
        else
        {
            this._cgl.gl.renderbufferStorage(this._cgl.gl.RENDERBUFFER, depthType, this._width, this._height);
        }

        this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._depthRenderbuffer);
    }

    // this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null);
    // this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._textureFrameBuffer);

    this._drawTargetArray.length = 0;
    for (i = 0; i < this._numRenderBuffers; i++) this._drawTargetArray.push(this._cgl.gl.COLOR_ATTACHMENT0 + i);

    // this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null);


    if (!this._cgl.gl.isFramebuffer(this._textureFrameBuffer)) this._log.warn("invalid framebuffer");// throw new Error("Invalid framebuffer");
    const status = this._cgl.gl.checkFramebufferStatus(this._cgl.gl.FRAMEBUFFER);

    if (status != this._cgl.gl.FRAMEBUFFER_COMPLETE)
    {
        this._log.error("framebuffer incomplete: " + this.name, this);
        this._log.log("options", this._options);
        this._log.log("options pixelformat", this._options.pixelFormat);

        switch (status)
        {
        case this._cgl.gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
            this._log.warn("FRAMEBUFFER_INCOMPLETE_ATTACHMENT...", this);
            throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
        case this._cgl.gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
            this._log.warn("FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
            throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
        case this._cgl.gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
            this._log.warn("FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
            throw new Error("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
        case this._cgl.gl.FRAMEBUFFER_UNSUPPORTED:
            this._log.warn("FRAMEBUFFER_UNSUPPORTED");
            throw new Error("Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED");
        default:
            this.valid = false;
            this._log.error("incomplete framebuffer", status, this._frameBuffer);
            this._cgl.printError();

            this._frameBuffer = null;
            // debugger;
            throw new Error("Incomplete framebuffer: " + status);

        // throw("Incomplete framebuffer: " + status);
        }
    }

    this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null);
    this._cgl.gl.bindRenderbuffer(this._cgl.gl.RENDERBUFFER, null);

    // this._cgl.printError("fb setsize");
};

Framebuffer2.prototype.renderStart = function ()
{
    if (this._disposed) return this._log.warn("disposed framebuffer renderStart...");
    this._cgl.checkFrameStarted("fb2 renderstart");
    this._cgl.pushModelMatrix(); // needed ??

    this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuffer);
    this._cgl.pushGlFrameBuffer(this._frameBuffer);
    this._cgl.pushFrameBuffer(this);

    this._cgl.pushPMatrix();
    this._cgl.pushViewPort(0, 0, this._width, this._height);

    this._cgl.gl.drawBuffers(this._drawTargetArray);

    if (this._options.clear)
    {
        this._cgl.gl.clearColor(0, 0, 0, 0);
        this._cgl.gl.clear(this._cgl.gl.COLOR_BUFFER_BIT | this._cgl.gl.DEPTH_BUFFER_BIT);
    }
};

Framebuffer2.prototype.clear = function ()
{
    if (this._numRenderBuffers <= 1)
    {
        this._cgl.gl.bindFramebuffer(this._cgl.gl.READ_FRAMEBUFFER, this._frameBuffer);
        this._cgl.gl.bindFramebuffer(this._cgl.gl.DRAW_FRAMEBUFFER, this._textureFrameBuffer);
    }
    else this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._frameBuffer);

    this._cgl.gl.drawBuffers(this._drawTargetArray);

    for (let i = 0; i < this._numRenderBuffers; i++)
    {
        this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0 + i, this._cgl.gl.TEXTURE_2D, this._colorTextures[i].tex, 0);
        this._cgl.gl.clearBufferfv(this._cgl.gl.COLOR, i, this.clearColors[i]);
    }
    this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null);
};

Framebuffer2.prototype.renderEnd = function ()
{
    if (this._disposed) return this._log.warn("disposed framebuffer renderEnd...");
    this._cgl.popPMatrix();

    this._cgl.profileData.profileFramebuffer++;


    if (this._numRenderBuffers <= 1)
    {
        this._cgl.gl.bindFramebuffer(this._cgl.gl.READ_FRAMEBUFFER, this._frameBuffer);
        this._cgl.gl.bindFramebuffer(this._cgl.gl.DRAW_FRAMEBUFFER, this._textureFrameBuffer);

        this._cgl.gl.clearBufferfv(this._cgl.gl.COLOR, 0, [0.0, 0.0, 0.0, 1.0]);
        this._cgl.gl.blitFramebuffer(0, 0, this._width, this._height, 0, 0, this._width, this._height, this._cgl.gl.COLOR_BUFFER_BIT | this._cgl.gl.DEPTH_BUFFER_BIT, this._cgl.gl.NEAREST);
    }
    else
    {
        this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this.Framebuffer2BlittingFramebuffer);
        this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.RENDERBUFFER, this._depthRenderbuffer);

        this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this.Framebuffer2FinalFramebuffer);
        this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.DEPTH_ATTACHMENT, this._cgl.gl.TEXTURE_2D, this._textureDepth.tex, 0);

        for (let i = 0; i < this._numRenderBuffers; i++)
        {
            this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this.Framebuffer2BlittingFramebuffer);
            this._cgl.gl.framebufferRenderbuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.RENDERBUFFER, this._colorRenderbuffers[i]);


            this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this.Framebuffer2FinalFramebuffer);
            this._cgl.gl.framebufferTexture2D(this._cgl.gl.FRAMEBUFFER, this._cgl.gl.COLOR_ATTACHMENT0, this._cgl.gl.TEXTURE_2D, this._colorTextures[i].tex, 0);

            this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, null);

            this._cgl.gl.bindFramebuffer(this._cgl.gl.READ_FRAMEBUFFER, this.Framebuffer2BlittingFramebuffer);
            this._cgl.gl.bindFramebuffer(this._cgl.gl.DRAW_FRAMEBUFFER, this.Framebuffer2FinalFramebuffer);

            // this._cgl.gl.clearBufferfv(this._cgl.gl.COLOR, i, [0.0, 0.0, 0.0, 1.0]);



            let flags = this._cgl.gl.COLOR_BUFFER_BIT;
            if (i == 0) flags |= this._cgl.gl.DEPTH_BUFFER_BIT;

            this._cgl.gl.blitFramebuffer(0, 0, this._width, this._height, 0, 0, this._width, this._height, flags, this._cgl.gl.NEAREST);
        }
    }

    this._cgl.gl.bindFramebuffer(this._cgl.gl.FRAMEBUFFER, this._cgl.popGlFrameBuffer());
    this._cgl.popFrameBuffer();

    this._cgl.popModelMatrix();
    // this._cgl.resetViewPort();
    this._cgl.popViewPort();


    if (this._colorTextures[0].filter == Texture.FILTER_MIPMAP)
    {
        for (let i = 0; i < this._numRenderBuffers; i++)
        {
            this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, this._colorTextures[i].tex);
            this._colorTextures[i].updateMipMap();
            this._cgl.gl.bindTexture(this._cgl.gl.TEXTURE_2D, null);
        }
    }
};



/// ///////

;// CONCATENATED MODULE: ./src/core/cgl/cgl_marker.js
const Marker = function (_cgl) // deprecated...
{
    this.draw = function (cgl, _size, depthTest) {};
};

const WirePoint = function (cgl) // deprecated...
{
    this.render = function (_cgl, _size) {};
};

const WireCube = function (cgl) // deprecated...
{
    this.render = function (_cgl, sizeX, sizeY, sizeZ) {};
};

;// CONCATENATED MODULE: ./src/core/cgl/cgl_unicolorshader.js


class UniColorShader
{
    constructor(_cgl)
    {
        this.shader = new CGL.Shader(_cgl, "markermaterial");

        const frag = ""
            .endl() + "void main()"
            .endl() + "{"
            .endl() + "    outColor = vec4(color.rgb,1.0);"
            .endl() + "}";


        const vert = ""
            .endl() + "IN vec3 vPosition;"
            .endl() + "UNI mat4 projMatrix;"
            .endl() + "UNI mat4 mvMatrix;"

            .endl() + "void main()"
            .endl() + "{"
            .endl() + "   gl_Position = projMatrix * mvMatrix * vec4(vPosition,1.0);"
            .endl() + "}";

        this.shader.setSource(vert, frag);
        this.coloruni = this.shader.addUniformFrag("4f", "color", [1, 0.777, 1, 1]);
    }

    setColor(r, g, b, a)
    {
        this.coloruni.set(r, g, b, a);
    }
}

;// CONCATENATED MODULE: ./src/core/cgl/index.js






















const cgl_CGL = {
    "Framebuffer": Framebuffer,
    "Framebuffer2": Framebuffer2,
    "Geometry": Geometry,
    "BoundingBox": BoundingBox,
    "Marker": Marker,
    "WirePoint": WirePoint,
    "WireCube": WireCube,
    "MatrixStack": MatrixStack,
    "Mesh": Mesh,
    "MESH": MESH,
    "ShaderLibMods": ShaderLibMods,
    "Shader": Shader,
    "Uniform": Uniform,
    "MESHES": MESHES,
    "Context": Context,
    "Texture": Texture,
    "TextureEffect": TextureEffect,
    "isWindows": isWindows,
    "getWheelSpeed": getWheelSpeed,
    "getWheelDelta": getWheelDelta,
    "onLoadingAssetsFinished": onLoadingAssetsFinished,
    "ProfileData": ProfileData,
    "UniColorShader": UniColorShader,
    ...constants_CONSTANTS.BLEND_MODES,
    ...constants_CONSTANTS.SHADER,
    ...constants_CONSTANTS.MATH,
    ...constants_CONSTANTS.BLEND_MODES,
};

window.CGL = cgl_CGL;





;// CONCATENATED MODULE: ./src/core/index.js

















window.CABLES = window.CABLES || {};

CABLES.CGL = cgl_CGL;
CABLES.CG = CG;
CABLES.CGP = cgp_CGP;
CABLES.EMBED = EMBED;
CABLES.Link = Link;
CABLES.Port = Port;
CABLES.Op = Op;
CABLES.Profiler = Profiler;
CABLES.Patch = core_patch;
CABLES.Timer = Timer;
CABLES.WEBAUDIO = WEBAUDIO;
CABLES.Variable = Variable;
CABLES.LoadingStatus = LoadingStatus;
CABLES.now = now;
CABLES.internalNow = internalNow;



CABLES = Object.assign(CABLES,
    utils_namespaceObject,
    anim_namespaceObject,
    CONSTANTS.PORT,
    CONSTANTS.PACO,
    CONSTANTS.ANIM,
    CONSTANTS.OP
);

/* harmony default export */ const core = (CABLES);

if (!(function () { return !this; }())) console.warn("not in strict mode: index core"); // eslint-disable-line

CABLES = __webpack_exports__["default"];
/******/ })()
;


var CABLES = CABLES || {}; CABLES.build = {"timestamp":1736760273867,"created":"2025-01-13T09:24:33.867Z","git":{"branch":"master","commit":"0e07848fd62e35a0a77f09c4c90a3fcbd6cb9f8f","date":"1736756567","message":"canvasinfo"}};
(()=>{"use strict";var t={d:(n,a)=>{for(var r in a)t.o(a,r)&&!t.o(n,r)&&Object.defineProperty(n,r,{enumerable:!0,get:a[r]})},o:(t,n)=>Object.prototype.hasOwnProperty.call(t,n),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},n={};t.r(n),t.d(n,{ARRAY_TYPE:()=>f,EPSILON:()=>M,RANDOM:()=>l,equals:()=>d,setMatrixArrayType:()=>v,toRadian:()=>m});var a={};t.r(a),t.d(a,{LDU:()=>j,add:()=>z,adjoint:()=>S,clone:()=>y,copy:()=>p,create:()=>x,determinant:()=>R,equals:()=>Y,exactEquals:()=>Q,frob:()=>V,fromRotation:()=>D,fromScaling:()=>F,fromValues:()=>w,identity:()=>q,invert:()=>P,mul:()=>_,multiply:()=>T,multiplyScalar:()=>X,multiplyScalarAndAdd:()=>Z,rotate:()=>I,scale:()=>E,set:()=>g,str:()=>L,sub:()=>B,subtract:()=>O,transpose:()=>A});var r={};t.r(r),t.d(r,{add:()=>it,clone:()=>k,copy:()=>U,create:()=>N,determinant:()=>J,equals:()=>ft,exactEquals:()=>Mt,frob:()=>ot,fromRotation:()=>at,fromScaling:()=>rt,fromTranslation:()=>ut,fromValues:()=>C,identity:()=>W,invert:()=>H,mul:()=>lt,multiply:()=>K,multiplyScalar:()=>ct,multiplyScalarAndAdd:()=>st,rotate:()=>$,scale:()=>tt,set:()=>G,str:()=>et,sub:()=>vt,subtract:()=>ht,translate:()=>nt});var u={};t.r(u),t.d(u,{add:()=>Yt,adjoint:()=>At,clone:()=>dt,copy:()=>xt,create:()=>bt,determinant:()=>Pt,equals:()=>Nt,exactEquals:()=>Bt,frob:()=>Qt,fromMat2d:()=>Lt,fromMat4:()=>mt,fromQuat:()=>Vt,fromRotation:()=>Dt,fromScaling:()=>Ft,fromTranslation:()=>Et,fromValues:()=>yt,identity:()=>qt,invert:()=>gt,mul:()=>kt,multiply:()=>St,multiplyScalar:()=>Zt,multiplyScalarAndAdd:()=>_t,normalFromMat4:()=>jt,projection:()=>zt,rotate:()=>Tt,scale:()=>It,set:()=>pt,str:()=>Ot,sub:()=>Ut,subtract:()=>Xt,translate:()=>Rt,transpose:()=>wt});var e={};t.r(e),t.d(e,{add:()=>Ln,adjoint:()=>nn,clone:()=>Ct,copy:()=>Gt,create:()=>Wt,determinant:()=>an,equals:()=>Qn,exactEquals:()=>On,frob:()=>Fn,fromQuat:()=>An,fromQuat2:()=>xn,fromRotation:()=>ln,fromRotationTranslation:()=>dn,fromRotationTranslationScale:()=>wn,fromRotationTranslationScaleOrigin:()=>gn,fromScaling:()=>fn,fromTranslation:()=>Mn,fromValues:()=>Ht,fromXRotation:()=>vn,fromYRotation:()=>bn,fromZRotation:()=>mn,frustum:()=>Pn,getRotation:()=>qn,getScaling:()=>pn,getTranslation:()=>yn,identity:()=>Kt,invert:()=>tn,lookAt:()=>In,mul:()=>Yn,multiply:()=>rn,multiplyScalar:()=>jn,multiplyScalarAndAdd:()=>zn,ortho:()=>Tn,perspective:()=>Sn,perspectiveFromFieldOfView:()=>Rn,rotate:()=>on,rotateX:()=>hn,rotateY:()=>cn,rotateZ:()=>sn,scale:()=>en,set:()=>Jt,str:()=>Dn,sub:()=>Xn,subtract:()=>Vn,targetTo:()=>En,translate:()=>un,transpose:()=>$t});var o={};t.r(o),t.d(o,{add:()=>Wn,angle:()=>wa,bezier:()=>va,ceil:()=>Jn,clone:()=>_n,copy:()=>kn,create:()=>Zn,cross:()=>Ma,dist:()=>Da,distance:()=>ua,div:()=>Ea,divide:()=>Hn,dot:()=>sa,equals:()=>Sa,exactEquals:()=>Pa,floor:()=>Kn,forEach:()=>ja,fromValues:()=>Nn,hermite:()=>la,inverse:()=>ha,len:()=>La,length:()=>Bn,lerp:()=>fa,max:()=>ta,min:()=>$n,mul:()=>Ia,multiply:()=>Gn,negate:()=>ia,normalize:()=>ca,random:()=>ba,rotateX:()=>ya,rotateY:()=>pa,rotateZ:()=>qa,round:()=>na,scale:()=>aa,scaleAndAdd:()=>ra,set:()=>Un,sqrDist:()=>Fa,sqrLen:()=>Va,squaredDistance:()=>ea,squaredLength:()=>oa,str:()=>Aa,sub:()=>Ta,subtract:()=>Cn,transformMat3:()=>da,transformMat4:()=>ma,transformQuat:()=>xa,zero:()=>ga});var i={};t.r(i),t.d(i,{add:()=>Za,ceil:()=>ka,clone:()=>Oa,copy:()=>Ya,create:()=>za,cross:()=>or,dist:()=>xr,distance:()=>Ka,div:()=>dr,divide:()=>Na,dot:()=>er,equals:()=>vr,exactEquals:()=>lr,floor:()=>Ua,forEach:()=>wr,fromValues:()=>Qa,inverse:()=>rr,len:()=>pr,length:()=>tr,lerp:()=>ir,max:()=>Ca,min:()=>Wa,mul:()=>mr,multiply:()=>Ba,negate:()=>ar,normalize:()=>ur,random:()=>hr,round:()=>Ga,scale:()=>Ha,scaleAndAdd:()=>Ja,set:()=>Xa,sqrDist:()=>yr,sqrLen:()=>qr,squaredDistance:()=>$a,squaredLength:()=>nr,str:()=>fr,sub:()=>br,subtract:()=>_a,transformMat4:()=>cr,transformQuat:()=>sr,zero:()=>Mr});var h={};t.r(h),t.d(h,{add:()=>$r,calculateW:()=>Fr,clone:()=>Gr,conjugate:()=>Yr,copy:()=>Jr,create:()=>gr,dot:()=>au,equals:()=>su,exactEquals:()=>cu,exp:()=>Lr,fromEuler:()=>Zr,fromMat3:()=>Xr,fromValues:()=>Hr,getAngle:()=>Rr,getAxisAngle:()=>Sr,identity:()=>Ar,invert:()=>Qr,len:()=>eu,length:()=>uu,lerp:()=>ru,ln:()=>Vr,mul:()=>tu,multiply:()=>Tr,normalize:()=>hu,pow:()=>jr,random:()=>Or,rotateX:()=>Ir,rotateY:()=>Er,rotateZ:()=>Dr,rotationTo:()=>Mu,scale:()=>nu,set:()=>Kr,setAxes:()=>lu,setAxisAngle:()=>Pr,slerp:()=>zr,sqlerp:()=>fu,sqrLen:()=>iu,squaredLength:()=>ou,str:()=>_r});var c={};t.r(c),t.d(c,{add:()=>Ou,clone:()=>bu,conjugate:()=>Nu,copy:()=>wu,create:()=>vu,dot:()=>Zu,equals:()=>Ku,exactEquals:()=>Ju,fromMat4:()=>qu,fromRotation:()=>pu,fromRotationTranslation:()=>xu,fromRotationTranslationValues:()=>du,fromTranslation:()=>yu,fromValues:()=>mu,getDual:()=>Su,getReal:()=>Pu,getTranslation:()=>Iu,identity:()=>gu,invert:()=>Bu,len:()=>Uu,length:()=>ku,lerp:()=>_u,mul:()=>Yu,multiply:()=>Qu,normalize:()=>Gu,rotateAroundAxis:()=>zu,rotateByQuatAppend:()=>Vu,rotateByQuatPrepend:()=>ju,rotateX:()=>Du,rotateY:()=>Fu,rotateZ:()=>Lu,scale:()=>Xu,set:()=>Au,setDual:()=>Tu,setReal:()=>Ru,sqrLen:()=>Cu,squaredLength:()=>Wu,str:()=>Hu,translate:()=>Eu});var s={};t.r(s),t.d(s,{add:()=>ue,angle:()=>De,ceil:()=>he,clone:()=>te,copy:()=>ae,create:()=>$u,cross:()=>ge,dist:()=>Xe,distance:()=>be,div:()=>Ye,divide:()=>ie,dot:()=>we,equals:()=>je,exactEquals:()=>Ve,floor:()=>ce,forEach:()=>Be,fromValues:()=>ne,inverse:()=>pe,len:()=>ze,length:()=>de,lerp:()=>Ae,max:()=>Me,min:()=>se,mul:()=>Qe,multiply:()=>oe,negate:()=>ye,normalize:()=>qe,random:()=>Pe,rotate:()=>Ee,round:()=>fe,scale:()=>le,scaleAndAdd:()=>ve,set:()=>re,sqrDist:()=>Ze,sqrLen:()=>_e,squaredDistance:()=>me,squaredLength:()=>xe,str:()=>Le,sub:()=>Oe,subtract:()=>ee,transformMat2:()=>Se,transformMat2d:()=>Re,transformMat3:()=>Te,transformMat4:()=>Ie,zero:()=>Fe});var M=1e-6,f="undefined"!=typeof Float32Array?Float32Array:Array,l=Math.random;function v(t){f=t}var b=Math.PI/180;function m(t){return t*b}function d(t,n){return Math.abs(t-n)<=M*Math.max(1,Math.abs(t),Math.abs(n))}function x(){var t=new f(4);return f!=Float32Array&&(t[1]=0,t[2]=0),t[0]=1,t[3]=1,t}function y(t){var n=new f(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n}function p(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t}function q(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t}function w(t,n,a,r){var u=new f(4);return u[0]=t,u[1]=n,u[2]=a,u[3]=r,u}function g(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t}function A(t,n){if(t===n){var a=n[1];t[1]=n[2],t[2]=a}else t[0]=n[0],t[1]=n[2],t[2]=n[1],t[3]=n[3];return t}function P(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*e-u*r;return o?(o=1/o,t[0]=e*o,t[1]=-r*o,t[2]=-u*o,t[3]=a*o,t):null}function S(t,n){var a=n[0];return t[0]=n[3],t[1]=-n[1],t[2]=-n[2],t[3]=a,t}function R(t){return t[0]*t[3]-t[2]*t[1]}function T(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],h=a[1],c=a[2],s=a[3];return t[0]=r*i+e*h,t[1]=u*i+o*h,t[2]=r*c+e*s,t[3]=u*c+o*s,t}function I(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),h=Math.cos(a);return t[0]=r*h+e*i,t[1]=u*h+o*i,t[2]=r*-i+e*h,t[3]=u*-i+o*h,t}function E(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],h=a[1];return t[0]=r*i,t[1]=u*i,t[2]=e*h,t[3]=o*h,t}function D(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t}function F(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t}function L(t){return"mat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"}function V(t){return Math.hypot(t[0],t[1],t[2],t[3])}function j(t,n,a,r){return t[2]=r[2]/r[0],a[0]=r[0],a[1]=r[1],a[3]=r[3]-t[2]*a[1],[t,n,a]}function z(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t}function O(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}function Q(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]}function Y(t,n){var a=t[0],r=t[1],u=t[2],e=t[3],o=n[0],i=n[1],h=n[2],c=n[3];return Math.abs(a-o)<=M*Math.max(1,Math.abs(a),Math.abs(o))&&Math.abs(r-i)<=M*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-h)<=M*Math.max(1,Math.abs(u),Math.abs(h))&&Math.abs(e-c)<=M*Math.max(1,Math.abs(e),Math.abs(c))}function X(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t}function Z(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t}Math.hypot||(Math.hypot=function(){for(var t=0,n=arguments.length;n--;)t+=arguments[n]*arguments[n];return Math.sqrt(t)});var _=T,B=O;function N(){var t=new f(6);return f!=Float32Array&&(t[1]=0,t[2]=0,t[4]=0,t[5]=0),t[0]=1,t[3]=1,t}function k(t){var n=new f(6);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n}function U(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t}function W(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t}function C(t,n,a,r,u,e){var o=new f(6);return o[0]=t,o[1]=n,o[2]=a,o[3]=r,o[4]=u,o[5]=e,o}function G(t,n,a,r,u,e,o){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t}function H(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],h=a*e-r*u;return h?(h=1/h,t[0]=e*h,t[1]=-r*h,t[2]=-u*h,t[3]=a*h,t[4]=(u*i-e*o)*h,t[5]=(r*o-a*i)*h,t):null}function J(t){return t[0]*t[3]-t[1]*t[2]}function K(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=a[0],s=a[1],M=a[2],f=a[3],l=a[4],v=a[5];return t[0]=r*c+e*s,t[1]=u*c+o*s,t[2]=r*M+e*f,t[3]=u*M+o*f,t[4]=r*l+e*v+i,t[5]=u*l+o*v+h,t}function $(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=Math.sin(a),s=Math.cos(a);return t[0]=r*s+e*c,t[1]=u*s+o*c,t[2]=r*-c+e*s,t[3]=u*-c+o*s,t[4]=i,t[5]=h,t}function tt(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=a[0],s=a[1];return t[0]=r*c,t[1]=u*c,t[2]=e*s,t[3]=o*s,t[4]=i,t[5]=h,t}function nt(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=a[0],s=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=r*c+e*s+i,t[5]=u*c+o*s+h,t}function at(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=-a,t[3]=r,t[4]=0,t[5]=0,t}function rt(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=n[1],t[4]=0,t[5]=0,t}function ut(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=n[0],t[5]=n[1],t}function et(t){return"mat2d("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+")"}function ot(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],1)}function it(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t}function ht(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t}function ct(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t}function st(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t}function Mt(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]}function ft(t,n){var a=t[0],r=t[1],u=t[2],e=t[3],o=t[4],i=t[5],h=n[0],c=n[1],s=n[2],f=n[3],l=n[4],v=n[5];return Math.abs(a-h)<=M*Math.max(1,Math.abs(a),Math.abs(h))&&Math.abs(r-c)<=M*Math.max(1,Math.abs(r),Math.abs(c))&&Math.abs(u-s)<=M*Math.max(1,Math.abs(u),Math.abs(s))&&Math.abs(e-f)<=M*Math.max(1,Math.abs(e),Math.abs(f))&&Math.abs(o-l)<=M*Math.max(1,Math.abs(o),Math.abs(l))&&Math.abs(i-v)<=M*Math.max(1,Math.abs(i),Math.abs(v))}var lt=K,vt=ht;function bt(){var t=new f(9);return f!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[5]=0,t[6]=0,t[7]=0),t[0]=1,t[4]=1,t[8]=1,t}function mt(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[4],t[4]=n[5],t[5]=n[6],t[6]=n[8],t[7]=n[9],t[8]=n[10],t}function dt(t){var n=new f(9);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n}function xt(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t}function yt(t,n,a,r,u,e,o,i,h){var c=new f(9);return c[0]=t,c[1]=n,c[2]=a,c[3]=r,c[4]=u,c[5]=e,c[6]=o,c[7]=i,c[8]=h,c}function pt(t,n,a,r,u,e,o,i,h,c){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=h,t[8]=c,t}function qt(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function wt(t,n){if(t===n){var a=n[1],r=n[2],u=n[5];t[1]=n[3],t[2]=n[6],t[3]=a,t[5]=n[7],t[6]=r,t[7]=u}else t[0]=n[0],t[1]=n[3],t[2]=n[6],t[3]=n[1],t[4]=n[4],t[5]=n[7],t[6]=n[2],t[7]=n[5],t[8]=n[8];return t}function gt(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8],M=s*o-i*c,f=-s*e+i*h,l=c*e-o*h,v=a*M+r*f+u*l;return v?(v=1/v,t[0]=M*v,t[1]=(-s*r+u*c)*v,t[2]=(i*r-u*o)*v,t[3]=f*v,t[4]=(s*a-u*h)*v,t[5]=(-i*a+u*e)*v,t[6]=l*v,t[7]=(-c*a+r*h)*v,t[8]=(o*a-r*e)*v,t):null}function At(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8];return t[0]=o*s-i*c,t[1]=u*c-r*s,t[2]=r*i-u*o,t[3]=i*h-e*s,t[4]=a*s-u*h,t[5]=u*e-a*i,t[6]=e*c-o*h,t[7]=r*h-a*c,t[8]=a*o-r*e,t}function Pt(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],h=t[7],c=t[8];return n*(c*e-o*h)+a*(-c*u+o*i)+r*(h*u-e*i)}function St(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=a[0],l=a[1],v=a[2],b=a[3],m=a[4],d=a[5],x=a[6],y=a[7],p=a[8];return t[0]=f*r+l*o+v*c,t[1]=f*u+l*i+v*s,t[2]=f*e+l*h+v*M,t[3]=b*r+m*o+d*c,t[4]=b*u+m*i+d*s,t[5]=b*e+m*h+d*M,t[6]=x*r+y*o+p*c,t[7]=x*u+y*i+p*s,t[8]=x*e+y*h+p*M,t}function Rt(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=a[0],l=a[1];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=h,t[6]=f*r+l*o+c,t[7]=f*u+l*i+s,t[8]=f*e+l*h+M,t}function Tt(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=Math.sin(a),l=Math.cos(a);return t[0]=l*r+f*o,t[1]=l*u+f*i,t[2]=l*e+f*h,t[3]=l*o-f*r,t[4]=l*i-f*u,t[5]=l*h-f*e,t[6]=c,t[7]=s,t[8]=M,t}function It(t,n,a){var r=a[0],u=a[1];return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=u*n[3],t[4]=u*n[4],t[5]=u*n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t}function Et(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=n[0],t[7]=n[1],t[8]=1,t}function Dt(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=-a,t[4]=r,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function Ft(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=n[1],t[5]=0,t[6]=0,t[7]=0,t[8]=1,t}function Lt(t,n){return t[0]=n[0],t[1]=n[1],t[2]=0,t[3]=n[2],t[4]=n[3],t[5]=0,t[6]=n[4],t[7]=n[5],t[8]=1,t}function Vt(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,h=u+u,c=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*h,b=e*o,m=e*i,d=e*h;return t[0]=1-M-v,t[3]=s-d,t[6]=f+m,t[1]=s+d,t[4]=1-c-v,t[7]=l-b,t[2]=f-m,t[5]=l+b,t[8]=1-c-M,t}function jt(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,y=a*h-u*o,p=a*c-e*o,q=r*h-u*i,w=r*c-e*i,g=u*c-e*h,A=s*b-M*v,P=s*m-f*v,S=s*d-l*v,R=M*m-f*b,T=M*d-l*b,I=f*d-l*m,E=x*I-y*T+p*R+q*S-w*P+g*A;return E?(E=1/E,t[0]=(i*I-h*T+c*R)*E,t[1]=(h*S-o*I-c*P)*E,t[2]=(o*T-i*S+c*A)*E,t[3]=(u*T-r*I-e*R)*E,t[4]=(a*I-u*S+e*P)*E,t[5]=(r*S-a*T-e*A)*E,t[6]=(b*g-m*w+d*q)*E,t[7]=(m*p-v*g-d*y)*E,t[8]=(v*w-b*p+d*x)*E,t):null}function zt(t,n,a){return t[0]=2/n,t[1]=0,t[2]=0,t[3]=0,t[4]=-2/a,t[5]=0,t[6]=-1,t[7]=1,t[8]=1,t}function Ot(t){return"mat3("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+")"}function Qt(t){return Math.hypot(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8])}function Yt(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t}function Xt(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t}function Zt(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t}function _t(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t}function Bt(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]}function Nt(t,n){var a=t[0],r=t[1],u=t[2],e=t[3],o=t[4],i=t[5],h=t[6],c=t[7],s=t[8],f=n[0],l=n[1],v=n[2],b=n[3],m=n[4],d=n[5],x=n[6],y=n[7],p=n[8];return Math.abs(a-f)<=M*Math.max(1,Math.abs(a),Math.abs(f))&&Math.abs(r-l)<=M*Math.max(1,Math.abs(r),Math.abs(l))&&Math.abs(u-v)<=M*Math.max(1,Math.abs(u),Math.abs(v))&&Math.abs(e-b)<=M*Math.max(1,Math.abs(e),Math.abs(b))&&Math.abs(o-m)<=M*Math.max(1,Math.abs(o),Math.abs(m))&&Math.abs(i-d)<=M*Math.max(1,Math.abs(i),Math.abs(d))&&Math.abs(h-x)<=M*Math.max(1,Math.abs(h),Math.abs(x))&&Math.abs(c-y)<=M*Math.max(1,Math.abs(c),Math.abs(y))&&Math.abs(s-p)<=M*Math.max(1,Math.abs(s),Math.abs(p))}var kt=St,Ut=Xt;function Wt(){var t=new f(16);return f!=Float32Array&&(t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=0,t[12]=0,t[13]=0,t[14]=0),t[0]=1,t[5]=1,t[10]=1,t[15]=1,t}function Ct(t){var n=new f(16);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n[8]=t[8],n[9]=t[9],n[10]=t[10],n[11]=t[11],n[12]=t[12],n[13]=t[13],n[14]=t[14],n[15]=t[15],n}function Gt(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t}function Ht(t,n,a,r,u,e,o,i,h,c,s,M,l,v,b,m){var d=new f(16);return d[0]=t,d[1]=n,d[2]=a,d[3]=r,d[4]=u,d[5]=e,d[6]=o,d[7]=i,d[8]=h,d[9]=c,d[10]=s,d[11]=M,d[12]=l,d[13]=v,d[14]=b,d[15]=m,d}function Jt(t,n,a,r,u,e,o,i,h,c,s,M,f,l,v,b,m){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=h,t[8]=c,t[9]=s,t[10]=M,t[11]=f,t[12]=l,t[13]=v,t[14]=b,t[15]=m,t}function Kt(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function $t(t,n){if(t===n){var a=n[1],r=n[2],u=n[3],e=n[6],o=n[7],i=n[11];t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=a,t[6]=n[9],t[7]=n[13],t[8]=r,t[9]=e,t[11]=n[14],t[12]=u,t[13]=o,t[14]=i}else t[0]=n[0],t[1]=n[4],t[2]=n[8],t[3]=n[12],t[4]=n[1],t[5]=n[5],t[6]=n[9],t[7]=n[13],t[8]=n[2],t[9]=n[6],t[10]=n[10],t[11]=n[14],t[12]=n[3],t[13]=n[7],t[14]=n[11],t[15]=n[15];return t}function tn(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15],x=a*i-r*o,y=a*h-u*o,p=a*c-e*o,q=r*h-u*i,w=r*c-e*i,g=u*c-e*h,A=s*b-M*v,P=s*m-f*v,S=s*d-l*v,R=M*m-f*b,T=M*d-l*b,I=f*d-l*m,E=x*I-y*T+p*R+q*S-w*P+g*A;return E?(E=1/E,t[0]=(i*I-h*T+c*R)*E,t[1]=(u*T-r*I-e*R)*E,t[2]=(b*g-m*w+d*q)*E,t[3]=(f*w-M*g-l*q)*E,t[4]=(h*S-o*I-c*P)*E,t[5]=(a*I-u*S+e*P)*E,t[6]=(m*p-v*g-d*y)*E,t[7]=(s*g-f*p+l*y)*E,t[8]=(o*T-i*S+c*A)*E,t[9]=(r*S-a*T-e*A)*E,t[10]=(v*w-b*p+d*x)*E,t[11]=(M*p-s*w-l*x)*E,t[12]=(i*P-o*R-h*A)*E,t[13]=(a*R-r*P+u*A)*E,t[14]=(b*y-v*q-m*x)*E,t[15]=(s*q-M*y+f*x)*E,t):null}function nn(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=n[4],i=n[5],h=n[6],c=n[7],s=n[8],M=n[9],f=n[10],l=n[11],v=n[12],b=n[13],m=n[14],d=n[15];return t[0]=i*(f*d-l*m)-M*(h*d-c*m)+b*(h*l-c*f),t[1]=-(r*(f*d-l*m)-M*(u*d-e*m)+b*(u*l-e*f)),t[2]=r*(h*d-c*m)-i*(u*d-e*m)+b*(u*c-e*h),t[3]=-(r*(h*l-c*f)-i*(u*l-e*f)+M*(u*c-e*h)),t[4]=-(o*(f*d-l*m)-s*(h*d-c*m)+v*(h*l-c*f)),t[5]=a*(f*d-l*m)-s*(u*d-e*m)+v*(u*l-e*f),t[6]=-(a*(h*d-c*m)-o*(u*d-e*m)+v*(u*c-e*h)),t[7]=a*(h*l-c*f)-o*(u*l-e*f)+s*(u*c-e*h),t[8]=o*(M*d-l*b)-s*(i*d-c*b)+v*(i*l-c*M),t[9]=-(a*(M*d-l*b)-s*(r*d-e*b)+v*(r*l-e*M)),t[10]=a*(i*d-c*b)-o*(r*d-e*b)+v*(r*c-e*i),t[11]=-(a*(i*l-c*M)-o*(r*l-e*M)+s*(r*c-e*i)),t[12]=-(o*(M*m-f*b)-s*(i*m-h*b)+v*(i*f-h*M)),t[13]=a*(M*m-f*b)-s*(r*m-u*b)+v*(r*f-u*M),t[14]=-(a*(i*m-h*b)-o*(r*m-u*b)+v*(r*h-u*i)),t[15]=a*(i*f-h*M)-o*(r*f-u*M)+s*(r*h-u*i),t}function an(t){var n=t[0],a=t[1],r=t[2],u=t[3],e=t[4],o=t[5],i=t[6],h=t[7],c=t[8],s=t[9],M=t[10],f=t[11],l=t[12],v=t[13],b=t[14],m=t[15];return(n*o-a*e)*(M*m-f*b)-(n*i-r*e)*(s*m-f*v)+(n*h-u*e)*(s*b-M*v)+(a*i-r*o)*(c*m-f*l)-(a*h-u*o)*(c*b-M*l)+(r*h-u*i)*(c*v-s*l)}function rn(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],b=n[12],m=n[13],d=n[14],x=n[15],y=a[0],p=a[1],q=a[2],w=a[3];return t[0]=y*r+p*i+q*M+w*b,t[1]=y*u+p*h+q*f+w*m,t[2]=y*e+p*c+q*l+w*d,t[3]=y*o+p*s+q*v+w*x,y=a[4],p=a[5],q=a[6],w=a[7],t[4]=y*r+p*i+q*M+w*b,t[5]=y*u+p*h+q*f+w*m,t[6]=y*e+p*c+q*l+w*d,t[7]=y*o+p*s+q*v+w*x,y=a[8],p=a[9],q=a[10],w=a[11],t[8]=y*r+p*i+q*M+w*b,t[9]=y*u+p*h+q*f+w*m,t[10]=y*e+p*c+q*l+w*d,t[11]=y*o+p*s+q*v+w*x,y=a[12],p=a[13],q=a[14],w=a[15],t[12]=y*r+p*i+q*M+w*b,t[13]=y*u+p*h+q*f+w*m,t[14]=y*e+p*c+q*l+w*d,t[15]=y*o+p*s+q*v+w*x,t}function un(t,n,a){var r,u,e,o,i,h,c,s,M,f,l,v,b=a[0],m=a[1],d=a[2];return n===t?(t[12]=n[0]*b+n[4]*m+n[8]*d+n[12],t[13]=n[1]*b+n[5]*m+n[9]*d+n[13],t[14]=n[2]*b+n[6]*m+n[10]*d+n[14],t[15]=n[3]*b+n[7]*m+n[11]*d+n[15]):(r=n[0],u=n[1],e=n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=n[8],f=n[9],l=n[10],v=n[11],t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=i,t[5]=h,t[6]=c,t[7]=s,t[8]=M,t[9]=f,t[10]=l,t[11]=v,t[12]=r*b+i*m+M*d+n[12],t[13]=u*b+h*m+f*d+n[13],t[14]=e*b+c*m+l*d+n[14],t[15]=o*b+s*m+v*d+n[15]),t}function en(t,n,a){var r=a[0],u=a[1],e=a[2];return t[0]=n[0]*r,t[1]=n[1]*r,t[2]=n[2]*r,t[3]=n[3]*r,t[4]=n[4]*u,t[5]=n[5]*u,t[6]=n[6]*u,t[7]=n[7]*u,t[8]=n[8]*e,t[9]=n[9]*e,t[10]=n[10]*e,t[11]=n[11]*e,t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t}function on(t,n,a,r){var u,e,o,i,h,c,s,f,l,v,b,m,d,x,y,p,q,w,g,A,P,S,R,T,I=r[0],E=r[1],D=r[2],F=Math.hypot(I,E,D);return F<M?null:(I*=F=1/F,E*=F,D*=F,u=Math.sin(a),o=1-(e=Math.cos(a)),i=n[0],h=n[1],c=n[2],s=n[3],f=n[4],l=n[5],v=n[6],b=n[7],m=n[8],d=n[9],x=n[10],y=n[11],p=I*I*o+e,q=E*I*o+D*u,w=D*I*o-E*u,g=I*E*o-D*u,A=E*E*o+e,P=D*E*o+I*u,S=I*D*o+E*u,R=E*D*o-I*u,T=D*D*o+e,t[0]=i*p+f*q+m*w,t[1]=h*p+l*q+d*w,t[2]=c*p+v*q+x*w,t[3]=s*p+b*q+y*w,t[4]=i*g+f*A+m*P,t[5]=h*g+l*A+d*P,t[6]=c*g+v*A+x*P,t[7]=s*g+b*A+y*P,t[8]=i*S+f*R+m*T,t[9]=h*S+l*R+d*T,t[10]=c*S+v*R+x*T,t[11]=s*S+b*R+y*T,n!==t&&(t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t)}function hn(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[4],o=n[5],i=n[6],h=n[7],c=n[8],s=n[9],M=n[10],f=n[11];return n!==t&&(t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[4]=e*u+c*r,t[5]=o*u+s*r,t[6]=i*u+M*r,t[7]=h*u+f*r,t[8]=c*u-e*r,t[9]=s*u-o*r,t[10]=M*u-i*r,t[11]=f*u-h*r,t}function cn(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[0],o=n[1],i=n[2],h=n[3],c=n[8],s=n[9],M=n[10],f=n[11];return n!==t&&(t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[0]=e*u-c*r,t[1]=o*u-s*r,t[2]=i*u-M*r,t[3]=h*u-f*r,t[8]=e*r+c*u,t[9]=o*r+s*u,t[10]=i*r+M*u,t[11]=h*r+f*u,t}function sn(t,n,a){var r=Math.sin(a),u=Math.cos(a),e=n[0],o=n[1],i=n[2],h=n[3],c=n[4],s=n[5],M=n[6],f=n[7];return n!==t&&(t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15]),t[0]=e*u+c*r,t[1]=o*u+s*r,t[2]=i*u+M*r,t[3]=h*u+f*r,t[4]=c*u-e*r,t[5]=s*u-o*r,t[6]=M*u-i*r,t[7]=f*u-h*r,t}function Mn(t,n){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=n[0],t[13]=n[1],t[14]=n[2],t[15]=1,t}function fn(t,n){return t[0]=n[0],t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=n[1],t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=n[2],t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function ln(t,n,a){var r,u,e,o=a[0],i=a[1],h=a[2],c=Math.hypot(o,i,h);return c<M?null:(o*=c=1/c,i*=c,h*=c,r=Math.sin(n),e=1-(u=Math.cos(n)),t[0]=o*o*e+u,t[1]=i*o*e+h*r,t[2]=h*o*e-i*r,t[3]=0,t[4]=o*i*e-h*r,t[5]=i*i*e+u,t[6]=h*i*e+o*r,t[7]=0,t[8]=o*h*e+i*r,t[9]=i*h*e-o*r,t[10]=h*h*e+u,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t)}function vn(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=r,t[6]=a,t[7]=0,t[8]=0,t[9]=-a,t[10]=r,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function bn(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=0,t[2]=-a,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=a,t[9]=0,t[10]=r,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function mn(t,n){var a=Math.sin(n),r=Math.cos(n);return t[0]=r,t[1]=a,t[2]=0,t[3]=0,t[4]=-a,t[5]=r,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function dn(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=r+r,h=u+u,c=e+e,s=r*i,M=r*h,f=r*c,l=u*h,v=u*c,b=e*c,m=o*i,d=o*h,x=o*c;return t[0]=1-(l+b),t[1]=M+x,t[2]=f-d,t[3]=0,t[4]=M-x,t[5]=1-(s+b),t[6]=v+m,t[7]=0,t[8]=f+d,t[9]=v-m,t[10]=1-(s+l),t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t}function xn(t,n){var a=new f(3),r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=r*r+u*u+e*e+o*o;return M>0?(a[0]=2*(i*o+s*r+h*e-c*u)/M,a[1]=2*(h*o+s*u+c*r-i*e)/M,a[2]=2*(c*o+s*e+i*u-h*r)/M):(a[0]=2*(i*o+s*r+h*e-c*u),a[1]=2*(h*o+s*u+c*r-i*e),a[2]=2*(c*o+s*e+i*u-h*r)),dn(t,n,a),t}function yn(t,n){return t[0]=n[12],t[1]=n[13],t[2]=n[14],t}function pn(t,n){var a=n[0],r=n[1],u=n[2],e=n[4],o=n[5],i=n[6],h=n[8],c=n[9],s=n[10];return t[0]=Math.hypot(a,r,u),t[1]=Math.hypot(e,o,i),t[2]=Math.hypot(h,c,s),t}function qn(t,n){var a=new f(3);pn(a,n);var r=1/a[0],u=1/a[1],e=1/a[2],o=n[0]*r,i=n[1]*u,h=n[2]*e,c=n[4]*r,s=n[5]*u,M=n[6]*e,l=n[8]*r,v=n[9]*u,b=n[10]*e,m=o+s+b,d=0;return m>0?(d=2*Math.sqrt(m+1),t[3]=.25*d,t[0]=(M-v)/d,t[1]=(l-h)/d,t[2]=(i-c)/d):o>s&&o>b?(d=2*Math.sqrt(1+o-s-b),t[3]=(M-v)/d,t[0]=.25*d,t[1]=(i+c)/d,t[2]=(l+h)/d):s>b?(d=2*Math.sqrt(1+s-o-b),t[3]=(l-h)/d,t[0]=(i+c)/d,t[1]=.25*d,t[2]=(M+v)/d):(d=2*Math.sqrt(1+b-o-s),t[3]=(i-c)/d,t[0]=(l+h)/d,t[1]=(M+v)/d,t[2]=.25*d),t}function wn(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3],h=u+u,c=e+e,s=o+o,M=u*h,f=u*c,l=u*s,v=e*c,b=e*s,m=o*s,d=i*h,x=i*c,y=i*s,p=r[0],q=r[1],w=r[2];return t[0]=(1-(v+m))*p,t[1]=(f+y)*p,t[2]=(l-x)*p,t[3]=0,t[4]=(f-y)*q,t[5]=(1-(M+m))*q,t[6]=(b+d)*q,t[7]=0,t[8]=(l+x)*w,t[9]=(b-d)*w,t[10]=(1-(M+v))*w,t[11]=0,t[12]=a[0],t[13]=a[1],t[14]=a[2],t[15]=1,t}function gn(t,n,a,r,u){var e=n[0],o=n[1],i=n[2],h=n[3],c=e+e,s=o+o,M=i+i,f=e*c,l=e*s,v=e*M,b=o*s,m=o*M,d=i*M,x=h*c,y=h*s,p=h*M,q=r[0],w=r[1],g=r[2],A=u[0],P=u[1],S=u[2],R=(1-(b+d))*q,T=(l+p)*q,I=(v-y)*q,E=(l-p)*w,D=(1-(f+d))*w,F=(m+x)*w,L=(v+y)*g,V=(m-x)*g,j=(1-(f+b))*g;return t[0]=R,t[1]=T,t[2]=I,t[3]=0,t[4]=E,t[5]=D,t[6]=F,t[7]=0,t[8]=L,t[9]=V,t[10]=j,t[11]=0,t[12]=a[0]+A-(R*A+E*P+L*S),t[13]=a[1]+P-(T*A+D*P+V*S),t[14]=a[2]+S-(I*A+F*P+j*S),t[15]=1,t}function An(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a+a,i=r+r,h=u+u,c=a*o,s=r*o,M=r*i,f=u*o,l=u*i,v=u*h,b=e*o,m=e*i,d=e*h;return t[0]=1-M-v,t[1]=s+d,t[2]=f-m,t[3]=0,t[4]=s-d,t[5]=1-c-v,t[6]=l+b,t[7]=0,t[8]=f+m,t[9]=l-b,t[10]=1-c-M,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function Pn(t,n,a,r,u,e,o){var i=1/(a-n),h=1/(u-r),c=1/(e-o);return t[0]=2*e*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*e*h,t[6]=0,t[7]=0,t[8]=(a+n)*i,t[9]=(u+r)*h,t[10]=(o+e)*c,t[11]=-1,t[12]=0,t[13]=0,t[14]=o*e*2*c,t[15]=0,t}function Sn(t,n,a,r,u){var e,o=1/Math.tan(n/2);return t[0]=o/a,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=o,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[11]=-1,t[12]=0,t[13]=0,t[15]=0,null!=u&&u!==1/0?(e=1/(r-u),t[10]=(u+r)*e,t[14]=2*u*r*e):(t[10]=-1,t[14]=-2*r),t}function Rn(t,n,a,r){var u=Math.tan(n.upDegrees*Math.PI/180),e=Math.tan(n.downDegrees*Math.PI/180),o=Math.tan(n.leftDegrees*Math.PI/180),i=Math.tan(n.rightDegrees*Math.PI/180),h=2/(o+i),c=2/(u+e);return t[0]=h,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=c,t[6]=0,t[7]=0,t[8]=-(o-i)*h*.5,t[9]=(u-e)*c*.5,t[10]=r/(a-r),t[11]=-1,t[12]=0,t[13]=0,t[14]=r*a/(a-r),t[15]=0,t}function Tn(t,n,a,r,u,e,o){var i=1/(n-a),h=1/(r-u),c=1/(e-o);return t[0]=-2*i,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*h,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*c,t[11]=0,t[12]=(n+a)*i,t[13]=(u+r)*h,t[14]=(o+e)*c,t[15]=1,t}function In(t,n,a,r){var u,e,o,i,h,c,s,f,l,v,b=n[0],m=n[1],d=n[2],x=r[0],y=r[1],p=r[2],q=a[0],w=a[1],g=a[2];return Math.abs(b-q)<M&&Math.abs(m-w)<M&&Math.abs(d-g)<M?Kt(t):(s=b-q,f=m-w,l=d-g,u=y*(l*=v=1/Math.hypot(s,f,l))-p*(f*=v),e=p*(s*=v)-x*l,o=x*f-y*s,(v=Math.hypot(u,e,o))?(u*=v=1/v,e*=v,o*=v):(u=0,e=0,o=0),i=f*o-l*e,h=l*u-s*o,c=s*e-f*u,(v=Math.hypot(i,h,c))?(i*=v=1/v,h*=v,c*=v):(i=0,h=0,c=0),t[0]=u,t[1]=i,t[2]=s,t[3]=0,t[4]=e,t[5]=h,t[6]=f,t[7]=0,t[8]=o,t[9]=c,t[10]=l,t[11]=0,t[12]=-(u*b+e*m+o*d),t[13]=-(i*b+h*m+c*d),t[14]=-(s*b+f*m+l*d),t[15]=1,t)}function En(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=r[0],h=r[1],c=r[2],s=u-a[0],M=e-a[1],f=o-a[2],l=s*s+M*M+f*f;l>0&&(s*=l=1/Math.sqrt(l),M*=l,f*=l);var v=h*f-c*M,b=c*s-i*f,m=i*M-h*s;return(l=v*v+b*b+m*m)>0&&(v*=l=1/Math.sqrt(l),b*=l,m*=l),t[0]=v,t[1]=b,t[2]=m,t[3]=0,t[4]=M*m-f*b,t[5]=f*v-s*m,t[6]=s*b-M*v,t[7]=0,t[8]=s,t[9]=M,t[10]=f,t[11]=0,t[12]=u,t[13]=e,t[14]=o,t[15]=1,t}function Dn(t){return"mat4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+", "+t[8]+", "+t[9]+", "+t[10]+", "+t[11]+", "+t[12]+", "+t[13]+", "+t[14]+", "+t[15]+")"}function Fn(t){return Math.hypot(t[0],t[1],t[3],t[4],t[5],t[6],t[7],t[8],t[9],t[10],t[11],t[12],t[13],t[14],t[15])}function Ln(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t[8]=n[8]+a[8],t[9]=n[9]+a[9],t[10]=n[10]+a[10],t[11]=n[11]+a[11],t[12]=n[12]+a[12],t[13]=n[13]+a[13],t[14]=n[14]+a[14],t[15]=n[15]+a[15],t}function Vn(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t[4]=n[4]-a[4],t[5]=n[5]-a[5],t[6]=n[6]-a[6],t[7]=n[7]-a[7],t[8]=n[8]-a[8],t[9]=n[9]-a[9],t[10]=n[10]-a[10],t[11]=n[11]-a[11],t[12]=n[12]-a[12],t[13]=n[13]-a[13],t[14]=n[14]-a[14],t[15]=n[15]-a[15],t}function jn(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t[8]=n[8]*a,t[9]=n[9]*a,t[10]=n[10]*a,t[11]=n[11]*a,t[12]=n[12]*a,t[13]=n[13]*a,t[14]=n[14]*a,t[15]=n[15]*a,t}function zn(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t[4]=n[4]+a[4]*r,t[5]=n[5]+a[5]*r,t[6]=n[6]+a[6]*r,t[7]=n[7]+a[7]*r,t[8]=n[8]+a[8]*r,t[9]=n[9]+a[9]*r,t[10]=n[10]+a[10]*r,t[11]=n[11]+a[11]*r,t[12]=n[12]+a[12]*r,t[13]=n[13]+a[13]*r,t[14]=n[14]+a[14]*r,t[15]=n[15]+a[15]*r,t}function On(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]&&t[8]===n[8]&&t[9]===n[9]&&t[10]===n[10]&&t[11]===n[11]&&t[12]===n[12]&&t[13]===n[13]&&t[14]===n[14]&&t[15]===n[15]}function Qn(t,n){var a=t[0],r=t[1],u=t[2],e=t[3],o=t[4],i=t[5],h=t[6],c=t[7],s=t[8],f=t[9],l=t[10],v=t[11],b=t[12],m=t[13],d=t[14],x=t[15],y=n[0],p=n[1],q=n[2],w=n[3],g=n[4],A=n[5],P=n[6],S=n[7],R=n[8],T=n[9],I=n[10],E=n[11],D=n[12],F=n[13],L=n[14],V=n[15];return Math.abs(a-y)<=M*Math.max(1,Math.abs(a),Math.abs(y))&&Math.abs(r-p)<=M*Math.max(1,Math.abs(r),Math.abs(p))&&Math.abs(u-q)<=M*Math.max(1,Math.abs(u),Math.abs(q))&&Math.abs(e-w)<=M*Math.max(1,Math.abs(e),Math.abs(w))&&Math.abs(o-g)<=M*Math.max(1,Math.abs(o),Math.abs(g))&&Math.abs(i-A)<=M*Math.max(1,Math.abs(i),Math.abs(A))&&Math.abs(h-P)<=M*Math.max(1,Math.abs(h),Math.abs(P))&&Math.abs(c-S)<=M*Math.max(1,Math.abs(c),Math.abs(S))&&Math.abs(s-R)<=M*Math.max(1,Math.abs(s),Math.abs(R))&&Math.abs(f-T)<=M*Math.max(1,Math.abs(f),Math.abs(T))&&Math.abs(l-I)<=M*Math.max(1,Math.abs(l),Math.abs(I))&&Math.abs(v-E)<=M*Math.max(1,Math.abs(v),Math.abs(E))&&Math.abs(b-D)<=M*Math.max(1,Math.abs(b),Math.abs(D))&&Math.abs(m-F)<=M*Math.max(1,Math.abs(m),Math.abs(F))&&Math.abs(d-L)<=M*Math.max(1,Math.abs(d),Math.abs(L))&&Math.abs(x-V)<=M*Math.max(1,Math.abs(x),Math.abs(V))}var Yn=rn,Xn=Vn;function Zn(){var t=new f(3);return f!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t}function _n(t){var n=new f(3);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n}function Bn(t){var n=t[0],a=t[1],r=t[2];return Math.hypot(n,a,r)}function Nn(t,n,a){var r=new f(3);return r[0]=t,r[1]=n,r[2]=a,r}function kn(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t}function Un(t,n,a,r){return t[0]=n,t[1]=a,t[2]=r,t}function Wn(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t}function Cn(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t}function Gn(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t}function Hn(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t}function Jn(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t[2]=Math.ceil(n[2]),t}function Kn(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t[2]=Math.floor(n[2]),t}function $n(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t[2]=Math.min(n[2],a[2]),t}function ta(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t[2]=Math.max(n[2],a[2]),t}function na(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t[2]=Math.round(n[2]),t}function aa(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t}function ra(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t}function ua(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return Math.hypot(a,r,u)}function ea(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2];return a*a+r*r+u*u}function oa(t){var n=t[0],a=t[1],r=t[2];return n*n+a*a+r*r}function ia(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t}function ha(t,n){return t[0]=1/n[0],t[1]=1/n[1],t[2]=1/n[2],t}function ca(t,n){var a=n[0],r=n[1],u=n[2],e=a*a+r*r+u*u;return e>0&&(e=1/Math.sqrt(e)),t[0]=n[0]*e,t[1]=n[1]*e,t[2]=n[2]*e,t}function sa(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function Ma(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],h=a[2];return t[0]=u*h-e*i,t[1]=e*o-r*h,t[2]=r*i-u*o,t}function fa(t,n,a,r){var u=n[0],e=n[1],o=n[2];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t[2]=o+r*(a[2]-o),t}function la(t,n,a,r,u,e){var o=e*e,i=o*(2*e-3)+1,h=o*(e-2)+e,c=o*(e-1),s=o*(3-2*e);return t[0]=n[0]*i+a[0]*h+r[0]*c+u[0]*s,t[1]=n[1]*i+a[1]*h+r[1]*c+u[1]*s,t[2]=n[2]*i+a[2]*h+r[2]*c+u[2]*s,t}function va(t,n,a,r,u,e){var o=1-e,i=o*o,h=e*e,c=i*o,s=3*e*i,M=3*h*o,f=h*e;return t[0]=n[0]*c+a[0]*s+r[0]*M+u[0]*f,t[1]=n[1]*c+a[1]*s+r[1]*M+u[1]*f,t[2]=n[2]*c+a[2]*s+r[2]*M+u[2]*f,t}function ba(t,n){n=n||1;var a=2*l()*Math.PI,r=2*l()-1,u=Math.sqrt(1-r*r)*n;return t[0]=Math.cos(a)*u,t[1]=Math.sin(a)*u,t[2]=r*n,t}function ma(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[3]*r+a[7]*u+a[11]*e+a[15];return o=o||1,t[0]=(a[0]*r+a[4]*u+a[8]*e+a[12])/o,t[1]=(a[1]*r+a[5]*u+a[9]*e+a[13])/o,t[2]=(a[2]*r+a[6]*u+a[10]*e+a[14])/o,t}function da(t,n,a){var r=n[0],u=n[1],e=n[2];return t[0]=r*a[0]+u*a[3]+e*a[6],t[1]=r*a[1]+u*a[4]+e*a[7],t[2]=r*a[2]+u*a[5]+e*a[8],t}function xa(t,n,a){var r=a[0],u=a[1],e=a[2],o=a[3],i=n[0],h=n[1],c=n[2],s=u*c-e*h,M=e*i-r*c,f=r*h-u*i,l=u*f-e*M,v=e*s-r*f,b=r*M-u*s,m=2*o;return s*=m,M*=m,f*=m,l*=2,v*=2,b*=2,t[0]=i+s+l,t[1]=h+M+v,t[2]=c+f+b,t}function ya(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[0],e[1]=u[1]*Math.cos(r)-u[2]*Math.sin(r),e[2]=u[1]*Math.sin(r)+u[2]*Math.cos(r),t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t}function pa(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[2]*Math.sin(r)+u[0]*Math.cos(r),e[1]=u[1],e[2]=u[2]*Math.cos(r)-u[0]*Math.sin(r),t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t}function qa(t,n,a,r){var u=[],e=[];return u[0]=n[0]-a[0],u[1]=n[1]-a[1],u[2]=n[2]-a[2],e[0]=u[0]*Math.cos(r)-u[1]*Math.sin(r),e[1]=u[0]*Math.sin(r)+u[1]*Math.cos(r),e[2]=u[2],t[0]=e[0]+a[0],t[1]=e[1]+a[1],t[2]=e[2]+a[2],t}function wa(t,n){var a=Nn(t[0],t[1],t[2]),r=Nn(n[0],n[1],n[2]);ca(a,a),ca(r,r);var u=sa(a,r);return u>1?0:u<-1?Math.PI:Math.acos(u)}function ga(t){return t[0]=0,t[1]=0,t[2]=0,t}function Aa(t){return"vec3("+t[0]+", "+t[1]+", "+t[2]+")"}function Pa(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]}function Sa(t,n){var a=t[0],r=t[1],u=t[2],e=n[0],o=n[1],i=n[2];return Math.abs(a-e)<=M*Math.max(1,Math.abs(a),Math.abs(e))&&Math.abs(r-o)<=M*Math.max(1,Math.abs(r),Math.abs(o))&&Math.abs(u-i)<=M*Math.max(1,Math.abs(u),Math.abs(i))}var Ra,Ta=Cn,Ia=Gn,Ea=Hn,Da=ua,Fa=ea,La=Bn,Va=oa,ja=(Ra=Zn(),function(t,n,a,r,u,e){var o,i;for(n||(n=3),a||(a=0),i=r?Math.min(r*n+a,t.length):t.length,o=a;o<i;o+=n)Ra[0]=t[o],Ra[1]=t[o+1],Ra[2]=t[o+2],u(Ra,Ra,e),t[o]=Ra[0],t[o+1]=Ra[1],t[o+2]=Ra[2];return t});function za(){var t=new f(4);return f!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[3]=0),t}function Oa(t){var n=new f(4);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n}function Qa(t,n,a,r){var u=new f(4);return u[0]=t,u[1]=n,u[2]=a,u[3]=r,u}function Ya(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t}function Xa(t,n,a,r,u){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t}function Za(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t}function _a(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t[2]=n[2]-a[2],t[3]=n[3]-a[3],t}function Ba(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t[2]=n[2]*a[2],t[3]=n[3]*a[3],t}function Na(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t[2]=n[2]/a[2],t[3]=n[3]/a[3],t}function ka(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t[2]=Math.ceil(n[2]),t[3]=Math.ceil(n[3]),t}function Ua(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t[2]=Math.floor(n[2]),t[3]=Math.floor(n[3]),t}function Wa(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t[2]=Math.min(n[2],a[2]),t[3]=Math.min(n[3],a[3]),t}function Ca(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t[2]=Math.max(n[2],a[2]),t[3]=Math.max(n[3],a[3]),t}function Ga(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t[2]=Math.round(n[2]),t[3]=Math.round(n[3]),t}function Ha(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t}function Ja(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t[2]=n[2]+a[2]*r,t[3]=n[3]+a[3]*r,t}function Ka(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2],e=n[3]-t[3];return Math.hypot(a,r,u,e)}function $a(t,n){var a=n[0]-t[0],r=n[1]-t[1],u=n[2]-t[2],e=n[3]-t[3];return a*a+r*r+u*u+e*e}function tr(t){var n=t[0],a=t[1],r=t[2],u=t[3];return Math.hypot(n,a,r,u)}function nr(t){var n=t[0],a=t[1],r=t[2],u=t[3];return n*n+a*a+r*r+u*u}function ar(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=-n[3],t}function rr(t,n){return t[0]=1/n[0],t[1]=1/n[1],t[2]=1/n[2],t[3]=1/n[3],t}function ur(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e;return o>0&&(o=1/Math.sqrt(o)),t[0]=a*o,t[1]=r*o,t[2]=u*o,t[3]=e*o,t}function er(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]+t[3]*n[3]}function or(t,n,a,r){var u=a[0]*r[1]-a[1]*r[0],e=a[0]*r[2]-a[2]*r[0],o=a[0]*r[3]-a[3]*r[0],i=a[1]*r[2]-a[2]*r[1],h=a[1]*r[3]-a[3]*r[1],c=a[2]*r[3]-a[3]*r[2],s=n[0],M=n[1],f=n[2],l=n[3];return t[0]=M*c-f*h+l*i,t[1]=-s*c+f*o-l*e,t[2]=s*h-M*o+l*u,t[3]=-s*i+M*e-f*u,t}function ir(t,n,a,r){var u=n[0],e=n[1],o=n[2],i=n[3];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t[2]=o+r*(a[2]-o),t[3]=i+r*(a[3]-i),t}function hr(t,n){var a,r,u,e,o,i;n=n||1;do{o=(a=2*l()-1)*a+(r=2*l()-1)*r}while(o>=1);do{i=(u=2*l()-1)*u+(e=2*l()-1)*e}while(i>=1);var h=Math.sqrt((1-o)/i);return t[0]=n*a,t[1]=n*r,t[2]=n*u*h,t[3]=n*e*h,t}function cr(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3];return t[0]=a[0]*r+a[4]*u+a[8]*e+a[12]*o,t[1]=a[1]*r+a[5]*u+a[9]*e+a[13]*o,t[2]=a[2]*r+a[6]*u+a[10]*e+a[14]*o,t[3]=a[3]*r+a[7]*u+a[11]*e+a[15]*o,t}function sr(t,n,a){var r=n[0],u=n[1],e=n[2],o=a[0],i=a[1],h=a[2],c=a[3],s=c*r+i*e-h*u,M=c*u+h*r-o*e,f=c*e+o*u-i*r,l=-o*r-i*u-h*e;return t[0]=s*c+l*-o+M*-h-f*-i,t[1]=M*c+l*-i+f*-o-s*-h,t[2]=f*c+l*-h+s*-i-M*-o,t[3]=n[3],t}function Mr(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=0,t}function fr(t){return"vec4("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"}function lr(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]}function vr(t,n){var a=t[0],r=t[1],u=t[2],e=t[3],o=n[0],i=n[1],h=n[2],c=n[3];return Math.abs(a-o)<=M*Math.max(1,Math.abs(a),Math.abs(o))&&Math.abs(r-i)<=M*Math.max(1,Math.abs(r),Math.abs(i))&&Math.abs(u-h)<=M*Math.max(1,Math.abs(u),Math.abs(h))&&Math.abs(e-c)<=M*Math.max(1,Math.abs(e),Math.abs(c))}var br=_a,mr=Ba,dr=Na,xr=Ka,yr=$a,pr=tr,qr=nr,wr=function(){var t=za();return function(n,a,r,u,e,o){var i,h;for(a||(a=4),r||(r=0),h=u?Math.min(u*a+r,n.length):n.length,i=r;i<h;i+=a)t[0]=n[i],t[1]=n[i+1],t[2]=n[i+2],t[3]=n[i+3],e(t,t,o),n[i]=t[0],n[i+1]=t[1],n[i+2]=t[2],n[i+3]=t[3];return n}}();function gr(){var t=new f(4);return f!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0),t[3]=1,t}function Ar(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t}function Pr(t,n,a){a*=.5;var r=Math.sin(a);return t[0]=r*n[0],t[1]=r*n[1],t[2]=r*n[2],t[3]=Math.cos(a),t}function Sr(t,n){var a=2*Math.acos(n[3]),r=Math.sin(a/2);return r>M?(t[0]=n[0]/r,t[1]=n[1]/r,t[2]=n[2]/r):(t[0]=1,t[1]=0,t[2]=0),a}function Rr(t,n){var a=au(t,n);return Math.acos(2*a*a-1)}function Tr(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],h=a[1],c=a[2],s=a[3];return t[0]=r*s+o*i+u*c-e*h,t[1]=u*s+o*h+e*i-r*c,t[2]=e*s+o*c+r*h-u*i,t[3]=o*s-r*i-u*h-e*c,t}function Ir(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),h=Math.cos(a);return t[0]=r*h+o*i,t[1]=u*h+e*i,t[2]=e*h-u*i,t[3]=o*h-r*i,t}function Er(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),h=Math.cos(a);return t[0]=r*h-e*i,t[1]=u*h+o*i,t[2]=e*h+r*i,t[3]=o*h-u*i,t}function Dr(t,n,a){a*=.5;var r=n[0],u=n[1],e=n[2],o=n[3],i=Math.sin(a),h=Math.cos(a);return t[0]=r*h+u*i,t[1]=u*h-r*i,t[2]=e*h+o*i,t[3]=o*h-e*i,t}function Fr(t,n){var a=n[0],r=n[1],u=n[2];return t[0]=a,t[1]=r,t[2]=u,t[3]=Math.sqrt(Math.abs(1-a*a-r*r-u*u)),t}function Lr(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=Math.sqrt(a*a+r*r+u*u),i=Math.exp(e),h=o>0?i*Math.sin(o)/o:0;return t[0]=a*h,t[1]=r*h,t[2]=u*h,t[3]=i*Math.cos(o),t}function Vr(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=Math.sqrt(a*a+r*r+u*u),i=o>0?Math.atan2(o,e)/o:0;return t[0]=a*i,t[1]=r*i,t[2]=u*i,t[3]=.5*Math.log(a*a+r*r+u*u+e*e),t}function jr(t,n,a){return Vr(t,n),nu(t,t,a),Lr(t,t),t}function zr(t,n,a,r){var u,e,o,i,h,c=n[0],s=n[1],f=n[2],l=n[3],v=a[0],b=a[1],m=a[2],d=a[3];return(e=c*v+s*b+f*m+l*d)<0&&(e=-e,v=-v,b=-b,m=-m,d=-d),1-e>M?(u=Math.acos(e),o=Math.sin(u),i=Math.sin((1-r)*u)/o,h=Math.sin(r*u)/o):(i=1-r,h=r),t[0]=i*c+h*v,t[1]=i*s+h*b,t[2]=i*f+h*m,t[3]=i*l+h*d,t}function Or(t){var n=l(),a=l(),r=l(),u=Math.sqrt(1-n),e=Math.sqrt(n);return t[0]=u*Math.sin(2*Math.PI*a),t[1]=u*Math.cos(2*Math.PI*a),t[2]=e*Math.sin(2*Math.PI*r),t[3]=e*Math.cos(2*Math.PI*r),t}function Qr(t,n){var a=n[0],r=n[1],u=n[2],e=n[3],o=a*a+r*r+u*u+e*e,i=o?1/o:0;return t[0]=-a*i,t[1]=-r*i,t[2]=-u*i,t[3]=e*i,t}function Yr(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t}function Xr(t,n){var a,r=n[0]+n[4]+n[8];if(r>0)a=Math.sqrt(r+1),t[3]=.5*a,a=.5/a,t[0]=(n[5]-n[7])*a,t[1]=(n[6]-n[2])*a,t[2]=(n[1]-n[3])*a;else{var u=0;n[4]>n[0]&&(u=1),n[8]>n[3*u+u]&&(u=2);var e=(u+1)%3,o=(u+2)%3;a=Math.sqrt(n[3*u+u]-n[3*e+e]-n[3*o+o]+1),t[u]=.5*a,a=.5/a,t[3]=(n[3*e+o]-n[3*o+e])*a,t[e]=(n[3*e+u]+n[3*u+e])*a,t[o]=(n[3*o+u]+n[3*u+o])*a}return t}function Zr(t,n,a,r){var u=.5*Math.PI/180;n*=u,a*=u,r*=u;var e=Math.sin(n),o=Math.cos(n),i=Math.sin(a),h=Math.cos(a),c=Math.sin(r),s=Math.cos(r);return t[0]=e*h*s-o*i*c,t[1]=o*i*s+e*h*c,t[2]=o*h*c-e*i*s,t[3]=o*h*s+e*i*c,t}function _r(t){return"quat("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+")"}var Br,Nr,kr,Ur,Wr,Cr,Gr=Oa,Hr=Qa,Jr=Ya,Kr=Xa,$r=Za,tu=Tr,nu=Ha,au=er,ru=ir,uu=tr,eu=uu,ou=nr,iu=ou,hu=ur,cu=lr,su=vr,Mu=(Br=Zn(),Nr=Nn(1,0,0),kr=Nn(0,1,0),function(t,n,a){var r=sa(n,a);return r<-.999999?(Ma(Br,Nr,n),La(Br)<1e-6&&Ma(Br,kr,n),ca(Br,Br),Pr(t,Br,Math.PI),t):r>.999999?(t[0]=0,t[1]=0,t[2]=0,t[3]=1,t):(Ma(Br,n,a),t[0]=Br[0],t[1]=Br[1],t[2]=Br[2],t[3]=1+r,hu(t,t))}),fu=(Ur=gr(),Wr=gr(),function(t,n,a,r,u,e){return zr(Ur,n,u,e),zr(Wr,a,r,e),zr(t,Ur,Wr,2*e*(1-e)),t}),lu=(Cr=bt(),function(t,n,a,r){return Cr[0]=a[0],Cr[3]=a[1],Cr[6]=a[2],Cr[1]=r[0],Cr[4]=r[1],Cr[7]=r[2],Cr[2]=-n[0],Cr[5]=-n[1],Cr[8]=-n[2],hu(t,Xr(t,Cr))});function vu(){var t=new f(8);return f!=Float32Array&&(t[0]=0,t[1]=0,t[2]=0,t[4]=0,t[5]=0,t[6]=0,t[7]=0),t[3]=1,t}function bu(t){var n=new f(8);return n[0]=t[0],n[1]=t[1],n[2]=t[2],n[3]=t[3],n[4]=t[4],n[5]=t[5],n[6]=t[6],n[7]=t[7],n}function mu(t,n,a,r,u,e,o,i){var h=new f(8);return h[0]=t,h[1]=n,h[2]=a,h[3]=r,h[4]=u,h[5]=e,h[6]=o,h[7]=i,h}function du(t,n,a,r,u,e,o){var i=new f(8);i[0]=t,i[1]=n,i[2]=a,i[3]=r;var h=.5*u,c=.5*e,s=.5*o;return i[4]=h*r+c*a-s*n,i[5]=c*r+s*t-h*a,i[6]=s*r+h*n-c*t,i[7]=-h*t-c*n-s*a,i}function xu(t,n,a){var r=.5*a[0],u=.5*a[1],e=.5*a[2],o=n[0],i=n[1],h=n[2],c=n[3];return t[0]=o,t[1]=i,t[2]=h,t[3]=c,t[4]=r*c+u*h-e*i,t[5]=u*c+e*o-r*h,t[6]=e*c+r*i-u*o,t[7]=-r*o-u*i-e*h,t}function yu(t,n){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=.5*n[0],t[5]=.5*n[1],t[6]=.5*n[2],t[7]=0,t}function pu(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=0,t[5]=0,t[6]=0,t[7]=0,t}function qu(t,n){var a=gr();qn(a,n);var r=new f(3);return yn(r,n),xu(t,a,r),t}function wu(t,n){return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t}function gu(t){return t[0]=0,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t[6]=0,t[7]=0,t}function Au(t,n,a,r,u,e,o,i,h){return t[0]=n,t[1]=a,t[2]=r,t[3]=u,t[4]=e,t[5]=o,t[6]=i,t[7]=h,t}var Pu=Jr;function Su(t,n){return t[0]=n[4],t[1]=n[5],t[2]=n[6],t[3]=n[7],t}var Ru=Jr;function Tu(t,n){return t[4]=n[0],t[5]=n[1],t[6]=n[2],t[7]=n[3],t}function Iu(t,n){var a=n[4],r=n[5],u=n[6],e=n[7],o=-n[0],i=-n[1],h=-n[2],c=n[3];return t[0]=2*(a*c+e*o+r*h-u*i),t[1]=2*(r*c+e*i+u*o-a*h),t[2]=2*(u*c+e*h+a*i-r*o),t}function Eu(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=.5*a[0],h=.5*a[1],c=.5*a[2],s=n[4],M=n[5],f=n[6],l=n[7];return t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=o*i+u*c-e*h+s,t[5]=o*h+e*i-r*c+M,t[6]=o*c+r*h-u*i+f,t[7]=-r*i-u*h-e*c+l,t}function Du(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=i*o+s*r+h*e-c*u,f=h*o+s*u+c*r-i*e,l=c*o+s*e+i*u-h*r,v=s*o-i*r-h*u-c*e;return Ir(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t}function Fu(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=i*o+s*r+h*e-c*u,f=h*o+s*u+c*r-i*e,l=c*o+s*e+i*u-h*r,v=s*o-i*r-h*u-c*e;return Er(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t}function Lu(t,n,a){var r=-n[0],u=-n[1],e=-n[2],o=n[3],i=n[4],h=n[5],c=n[6],s=n[7],M=i*o+s*r+h*e-c*u,f=h*o+s*u+c*r-i*e,l=c*o+s*e+i*u-h*r,v=s*o-i*r-h*u-c*e;return Dr(t,n,a),r=t[0],u=t[1],e=t[2],o=t[3],t[4]=M*o+v*r+f*e-l*u,t[5]=f*o+v*u+l*r-M*e,t[6]=l*o+v*e+M*u-f*r,t[7]=v*o-M*r-f*u-l*e,t}function Vu(t,n,a){var r=a[0],u=a[1],e=a[2],o=a[3],i=n[0],h=n[1],c=n[2],s=n[3];return t[0]=i*o+s*r+h*e-c*u,t[1]=h*o+s*u+c*r-i*e,t[2]=c*o+s*e+i*u-h*r,t[3]=s*o-i*r-h*u-c*e,i=n[4],h=n[5],c=n[6],s=n[7],t[4]=i*o+s*r+h*e-c*u,t[5]=h*o+s*u+c*r-i*e,t[6]=c*o+s*e+i*u-h*r,t[7]=s*o-i*r-h*u-c*e,t}function ju(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[0],h=a[1],c=a[2],s=a[3];return t[0]=r*s+o*i+u*c-e*h,t[1]=u*s+o*h+e*i-r*c,t[2]=e*s+o*c+r*h-u*i,t[3]=o*s-r*i-u*h-e*c,i=a[4],h=a[5],c=a[6],s=a[7],t[4]=r*s+o*i+u*c-e*h,t[5]=u*s+o*h+e*i-r*c,t[6]=e*s+o*c+r*h-u*i,t[7]=o*s-r*i-u*h-e*c,t}function zu(t,n,a,r){if(Math.abs(r)<M)return wu(t,n);var u=Math.hypot(a[0],a[1],a[2]);r*=.5;var e=Math.sin(r),o=e*a[0]/u,i=e*a[1]/u,h=e*a[2]/u,c=Math.cos(r),s=n[0],f=n[1],l=n[2],v=n[3];t[0]=s*c+v*o+f*h-l*i,t[1]=f*c+v*i+l*o-s*h,t[2]=l*c+v*h+s*i-f*o,t[3]=v*c-s*o-f*i-l*h;var b=n[4],m=n[5],d=n[6],x=n[7];return t[4]=b*c+x*o+m*h-d*i,t[5]=m*c+x*i+d*o-b*h,t[6]=d*c+x*h+b*i-m*o,t[7]=x*c-b*o-m*i-d*h,t}function Ou(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t[2]=n[2]+a[2],t[3]=n[3]+a[3],t[4]=n[4]+a[4],t[5]=n[5]+a[5],t[6]=n[6]+a[6],t[7]=n[7]+a[7],t}function Qu(t,n,a){var r=n[0],u=n[1],e=n[2],o=n[3],i=a[4],h=a[5],c=a[6],s=a[7],M=n[4],f=n[5],l=n[6],v=n[7],b=a[0],m=a[1],d=a[2],x=a[3];return t[0]=r*x+o*b+u*d-e*m,t[1]=u*x+o*m+e*b-r*d,t[2]=e*x+o*d+r*m-u*b,t[3]=o*x-r*b-u*m-e*d,t[4]=r*s+o*i+u*c-e*h+M*x+v*b+f*d-l*m,t[5]=u*s+o*h+e*i-r*c+f*x+v*m+l*b-M*d,t[6]=e*s+o*c+r*h-u*i+l*x+v*d+M*m-f*b,t[7]=o*s-r*i-u*h-e*c+v*x-M*b-f*m-l*d,t}var Yu=Qu;function Xu(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t[2]=n[2]*a,t[3]=n[3]*a,t[4]=n[4]*a,t[5]=n[5]*a,t[6]=n[6]*a,t[7]=n[7]*a,t}var Zu=au;function _u(t,n,a,r){var u=1-r;return Zu(n,a)<0&&(r=-r),t[0]=n[0]*u+a[0]*r,t[1]=n[1]*u+a[1]*r,t[2]=n[2]*u+a[2]*r,t[3]=n[3]*u+a[3]*r,t[4]=n[4]*u+a[4]*r,t[5]=n[5]*u+a[5]*r,t[6]=n[6]*u+a[6]*r,t[7]=n[7]*u+a[7]*r,t}function Bu(t,n){var a=Wu(n);return t[0]=-n[0]/a,t[1]=-n[1]/a,t[2]=-n[2]/a,t[3]=n[3]/a,t[4]=-n[4]/a,t[5]=-n[5]/a,t[6]=-n[6]/a,t[7]=n[7]/a,t}function Nu(t,n){return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=n[3],t[4]=-n[4],t[5]=-n[5],t[6]=-n[6],t[7]=n[7],t}var ku=uu,Uu=ku,Wu=ou,Cu=Wu;function Gu(t,n){var a=Wu(n);if(a>0){a=Math.sqrt(a);var r=n[0]/a,u=n[1]/a,e=n[2]/a,o=n[3]/a,i=n[4],h=n[5],c=n[6],s=n[7],M=r*i+u*h+e*c+o*s;t[0]=r,t[1]=u,t[2]=e,t[3]=o,t[4]=(i-r*M)/a,t[5]=(h-u*M)/a,t[6]=(c-e*M)/a,t[7]=(s-o*M)/a}return t}function Hu(t){return"quat2("+t[0]+", "+t[1]+", "+t[2]+", "+t[3]+", "+t[4]+", "+t[5]+", "+t[6]+", "+t[7]+")"}function Ju(t,n){return t[0]===n[0]&&t[1]===n[1]&&t[2]===n[2]&&t[3]===n[3]&&t[4]===n[4]&&t[5]===n[5]&&t[6]===n[6]&&t[7]===n[7]}function Ku(t,n){var a=t[0],r=t[1],u=t[2],e=t[3],o=t[4],i=t[5],h=t[6],c=t[7],s=n[0],f=n[1],l=n[2],v=n[3],b=n[4],m=n[5],d=n[6],x=n[7];return Math.abs(a-s)<=M*Math.max(1,Math.abs(a),Math.abs(s))&&Math.abs(r-f)<=M*Math.max(1,Math.abs(r),Math.abs(f))&&Math.abs(u-l)<=M*Math.max(1,Math.abs(u),Math.abs(l))&&Math.abs(e-v)<=M*Math.max(1,Math.abs(e),Math.abs(v))&&Math.abs(o-b)<=M*Math.max(1,Math.abs(o),Math.abs(b))&&Math.abs(i-m)<=M*Math.max(1,Math.abs(i),Math.abs(m))&&Math.abs(h-d)<=M*Math.max(1,Math.abs(h),Math.abs(d))&&Math.abs(c-x)<=M*Math.max(1,Math.abs(c),Math.abs(x))}function $u(){var t=new f(2);return f!=Float32Array&&(t[0]=0,t[1]=0),t}function te(t){var n=new f(2);return n[0]=t[0],n[1]=t[1],n}function ne(t,n){var a=new f(2);return a[0]=t,a[1]=n,a}function ae(t,n){return t[0]=n[0],t[1]=n[1],t}function re(t,n,a){return t[0]=n,t[1]=a,t}function ue(t,n,a){return t[0]=n[0]+a[0],t[1]=n[1]+a[1],t}function ee(t,n,a){return t[0]=n[0]-a[0],t[1]=n[1]-a[1],t}function oe(t,n,a){return t[0]=n[0]*a[0],t[1]=n[1]*a[1],t}function ie(t,n,a){return t[0]=n[0]/a[0],t[1]=n[1]/a[1],t}function he(t,n){return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t}function ce(t,n){return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t}function se(t,n,a){return t[0]=Math.min(n[0],a[0]),t[1]=Math.min(n[1],a[1]),t}function Me(t,n,a){return t[0]=Math.max(n[0],a[0]),t[1]=Math.max(n[1],a[1]),t}function fe(t,n){return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t}function le(t,n,a){return t[0]=n[0]*a,t[1]=n[1]*a,t}function ve(t,n,a,r){return t[0]=n[0]+a[0]*r,t[1]=n[1]+a[1]*r,t}function be(t,n){var a=n[0]-t[0],r=n[1]-t[1];return Math.hypot(a,r)}function me(t,n){var a=n[0]-t[0],r=n[1]-t[1];return a*a+r*r}function de(t){var n=t[0],a=t[1];return Math.hypot(n,a)}function xe(t){var n=t[0],a=t[1];return n*n+a*a}function ye(t,n){return t[0]=-n[0],t[1]=-n[1],t}function pe(t,n){return t[0]=1/n[0],t[1]=1/n[1],t}function qe(t,n){var a=n[0],r=n[1],u=a*a+r*r;return u>0&&(u=1/Math.sqrt(u)),t[0]=n[0]*u,t[1]=n[1]*u,t}function we(t,n){return t[0]*n[0]+t[1]*n[1]}function ge(t,n,a){var r=n[0]*a[1]-n[1]*a[0];return t[0]=t[1]=0,t[2]=r,t}function Ae(t,n,a,r){var u=n[0],e=n[1];return t[0]=u+r*(a[0]-u),t[1]=e+r*(a[1]-e),t}function Pe(t,n){n=n||1;var a=2*l()*Math.PI;return t[0]=Math.cos(a)*n,t[1]=Math.sin(a)*n,t}function Se(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u,t[1]=a[1]*r+a[3]*u,t}function Re(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[2]*u+a[4],t[1]=a[1]*r+a[3]*u+a[5],t}function Te(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[3]*u+a[6],t[1]=a[1]*r+a[4]*u+a[7],t}function Ie(t,n,a){var r=n[0],u=n[1];return t[0]=a[0]*r+a[4]*u+a[12],t[1]=a[1]*r+a[5]*u+a[13],t}function Ee(t,n,a,r){var u=n[0]-a[0],e=n[1]-a[1],o=Math.sin(r),i=Math.cos(r);return t[0]=u*i-e*o+a[0],t[1]=u*o+e*i+a[1],t}function De(t,n){var a=t[0],r=t[1],u=n[0],e=n[1],o=a*a+r*r;o>0&&(o=1/Math.sqrt(o));var i=u*u+e*e;i>0&&(i=1/Math.sqrt(i));var h=(a*u+r*e)*o*i;return h>1?0:h<-1?Math.PI:Math.acos(h)}function Fe(t){return t[0]=0,t[1]=0,t}function Le(t){return"vec2("+t[0]+", "+t[1]+")"}function Ve(t,n){return t[0]===n[0]&&t[1]===n[1]}function je(t,n){var a=t[0],r=t[1],u=n[0],e=n[1];return Math.abs(a-u)<=M*Math.max(1,Math.abs(a),Math.abs(u))&&Math.abs(r-e)<=M*Math.max(1,Math.abs(r),Math.abs(e))}var ze=de,Oe=ee,Qe=oe,Ye=ie,Xe=be,Ze=me,_e=xe,Be=function(){var t=$u();return function(n,a,r,u,e,o){var i,h;for(a||(a=2),r||(r=0),h=u?Math.min(u*a+r,n.length):n.length,i=r;i<h;i+=a)t[0]=n[i],t[1]=n[i+1],e(t,t,o),n[i]=t[0],n[i+1]=t[1];return n}}();window.glMatrix=n,window.mat2=a,window.mat2d=r,window.mat3=u,window.mat4=e,window.quat=h,window.quat2=c,window.vec2=s,window.vec3=o,window.vec4=i})();
//# sourceMappingURL=libs.core.js.map
if(!CABLES.exportedPatches)CABLES.exportedPatches={};CABLES.exportedPatches["M2N0xD"]={_id:"67b9b6372e8a72d24af4b2e8",ops:[{id:"ce2c71fc-8574-4d15-a8b3-8f348911ae04",uiAttribs:{},portsIn:[{name:"FPS Limit",value:0},{name:"Reduce FPS not focussed",value:1},{name:"Reduce FPS loading",value:0},{name:"Clear",value:1},{name:"ClearAlpha",value:1},{name:"Fullscreen Button",value:0},{name:"Active",value:1},{name:"Hires Displays",value:0},{name:"Pixel Unit index",value:0},{name:"Pixel Unit",value:"Display"}],portsOut:[{name:"trigger",links:[{portIn:"Execute",portOut:"trigger",objIn:"8ff6e941-1302-4c21-a705-6bbf479fa4ae",objOut:"ce2c71fc-8574-4d15-a8b3-8f348911ae04"}]},{name:"width",value:641},{name:"height",value:400}],objName:"Ops.Gl.MainLoop"},{id:"8ff6e941-1302-4c21-a705-6bbf479fa4ae",uiAttribs:{},portsIn:[{name:"duration",value:10}],portsOut:[{name:"trigger",links:[{portIn:"exe",portOut:"trigger",objIn:"984acd84-04d4-4e2f-a165-62ed3da0e5c5",objOut:"8ff6e941-1302-4c21-a705-6bbf479fa4ae"}]}],objName:"Ops.TimeLine.TimeLineLoop"},{id:"984acd84-04d4-4e2f-a165-62ed3da0e5c5",uiAttribs:{},portsOut:[{name:"trigger 0",links:[{portIn:"Render",portOut:"trigger 0",objIn:"48420caa-73f5-41a2-82b6-54ed4fe8ae45",objOut:"984acd84-04d4-4e2f-a165-62ed3da0e5c5"}]},{name:"trigger 2",links:[{portIn:"Render",portOut:"trigger 2",objIn:"3d2ba1c4-b1b4-441c-a32e-f88c27fda4f0",objOut:"984acd84-04d4-4e2f-a165-62ed3da0e5c5"}]},{name:"trigger 3",links:[{portIn:"render",portOut:"trigger 3",objIn:"dcc92e4e-8169-4086-96da-7439f25271a6",objOut:"984acd84-04d4-4e2f-a165-62ed3da0e5c5"}]},{name:"trigger 9",links:[{portIn:"render",portOut:"trigger 9",objIn:"89b063b3-bb76-438e-a1a8-424a6678ef66",objOut:"984acd84-04d4-4e2f-a165-62ed3da0e5c5"}]},{name:"trigger 15",links:[{portIn:"render",portOut:"trigger 15",objIn:"2c3831f3-3272-4d73-bf5e-f87904be7741",objOut:"984acd84-04d4-4e2f-a165-62ed3da0e5c5"}]}],objName:"Ops.Trigger.Sequence"},{id:"48420caa-73f5-41a2-82b6-54ed4fe8ae45",uiAttribs:{},portsIn:[{name:"Size index",value:0},{name:"Size",value:"Auto"},{name:"Width",value:640},{name:"Height",value:480},{name:"Filter index",value:0},{name:"Filter",value:"nearest"},{name:"Wrap index",value:1},{name:"Wrap",value:"repeat"},{name:"Pixel Format index",value:11},{name:"Pixel Format",value:"RGBA 32bit float"},{name:"R",value:.00018981933593753553},{name:"G",value:.00018981933593753553},{name:"B",value:.00018981933593753553},{name:"A",value:0}],portsOut:[{name:"Next",links:[{portIn:"render",portOut:"Next",objIn:"00e440e3-f5a3-4e93-be97-5fab29dd3d37",objOut:"48420caa-73f5-41a2-82b6-54ed4fe8ae45"}]},{name:"texture_out",links:[{portIn:"Texture",portOut:"texture_out",objIn:"89b063b3-bb76-438e-a1a8-424a6678ef66",objOut:"48420caa-73f5-41a2-82b6-54ed4fe8ae45"},{portIn:"Texture",portOut:"texture_out",objIn:"2c3831f3-3272-4d73-bf5e-f87904be7741",objOut:"48420caa-73f5-41a2-82b6-54ed4fe8ae45"}]},{name:"Aspect Ratio",value:1.6025},{name:"Texture Width",value:641},{name:"Texture Height",value:400}],objName:"Ops.Gl.ImageCompose.ImageCompose_v3"},{id:"7986ff15-d67f-45f7-bbbc-890e37165b31",uiAttribs:{},portsIn:[{name:"blendMode index",value:9},{name:"blendMode",value:"negation"},{name:"amount",value:.9,animated:true,anim:{keys:[{t:0,v:".2",e:0},{t:1.0333333333333334,v:".9",e:0},{t:9,v:".9",e:0},{t:10,v:".2",e:0}],loop:false}},{name:"Premultiplied",value:0},{name:"Alpha Mask",value:0},{name:"removeAlphaSrc",value:0},{name:"Mask Src index",value:0},{name:"Mask Src",value:"alpha channel"},{name:"Invert alpha channel",value:0},{name:"Aspect Ratio",value:0},{name:"Stretch Axis index",value:0},{name:"Stretch Axis",value:"X"},{name:"Position",value:0},{name:"Crop",value:0},{name:"flip x",value:1},{name:"flip y",value:1},{name:"Transform",value:1},{name:"Scale X",value:.4103950528964164,animated:true,anim:{keys:[{t:.3333333333333333,v:".1",e:13},{t:5,v:1,e:13},{t:8.106600000000093,v:".1",e:0}],loop:false}},{name:"Scale Y",value:.38400615585368314,animated:true,anim:{keys:[{t:0,v:.1,e:13},{t:5,v:.8,e:13},{t:10,v:.1,e:0}],loop:false}},{name:"Position X",value:0},{name:"Position Y",value:0},{name:"Rotation",value:0},{name:"Clip Repeat",value:0}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"de354a76-a1e1-4993-85de-bce4075ea1b5",objOut:"7986ff15-d67f-45f7-bbbc-890e37165b31"}]}],objName:"Ops.Gl.ImageCompose.DrawImage_v3"},{id:"de354a76-a1e1-4993-85de-bce4075ea1b5",uiAttribs:{},portsIn:[{name:"blendMode index",value:9},{name:"blendMode",value:"negation"},{name:"amount",value:1},{name:"Premultiplied",value:0},{name:"Alpha Mask",value:0},{name:"removeAlphaSrc",value:0},{name:"Mask Src index",value:0},{name:"Mask Src",value:"alpha channel"},{name:"Invert alpha channel",value:0},{name:"Aspect Ratio",value:0},{name:"Stretch Axis index",value:0},{name:"Stretch Axis",value:"X"},{name:"Position",value:0},{name:"Crop",value:0},{name:"flip x",value:1},{name:"flip y",value:0},{name:"Transform",value:1},{name:"Scale X",value:1},{name:"Scale Y",value:1},{name:"Position X",value:0},{name:"Position Y",value:0},{name:"Rotation",value:0},{name:"Clip Repeat",value:0}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"4b830f72-a5bd-4391-842a-5fbed03a4274",objOut:"de354a76-a1e1-4993-85de-bce4075ea1b5"}]}],objName:"Ops.Gl.ImageCompose.DrawImage_v3"},{id:"dcc92e4e-8169-4086-96da-7439f25271a6",uiAttribs:{},portsIn:[{name:"use viewport size",value:1},{name:"texture width",value:641},{name:"texture height",value:400},{name:"Auto Aspect",value:0},{name:"filter index",value:1},{name:"filter",value:"linear"},{name:"Wrap index",value:1},{name:"Wrap",value:"Repeat"},{name:"MSAA index",value:0},{name:"MSAA",value:"none"},{name:"HDR",value:0,title:"Pixelformat Float 32bit"},{name:"Depth",value:1},{name:"Clear",value:1}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"2f51a87d-2b26-4c4f-974b-e691f4705696",objOut:"dcc92e4e-8169-4086-96da-7439f25271a6"}]},{name:"texture",links:[{portIn:"Image",portOut:"texture",objIn:"de354a76-a1e1-4993-85de-bce4075ea1b5",objOut:"dcc92e4e-8169-4086-96da-7439f25271a6"}]}],objName:"Ops.Gl.RenderToTexture"},{id:"795226ab-c9f5-491e-9c18-271f3fadd58b",uiAttribs:{},portsIn:[{name:"time",value:2.6228923191639035,animated:true,anim:{keys:[{t:0,v:"1",e:13},{t:5,v:"5",e:13},{t:10,v:"1",e:0}],loop:false}},{name:"duration",value:1},{name:"offset",value:0},{name:"look ahead",value:0}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"20ef90b6-b959-49a4-987f-f64b421a9811",objOut:"795226ab-c9f5-491e-9c18-271f3fadd58b"},{portIn:"Render",portOut:"trigger",objIn:"51fb46b1-8a0c-4106-9793-62c5cfda9381",objOut:"795226ab-c9f5-491e-9c18-271f3fadd58b"}]},{name:"index",value:2.6228923191639035}],objName:"Ops.Gl.Matrix.ArrayPathFollow"},{id:"29b4af3d-a32a-41d6-a22d-be0d72bdc099",uiAttribs:{},portsIn:[{name:"percent",value:1},{name:"segments",value:6},{name:"radius",value:1,animated:true,anim:{keys:[{t:10,v:1,e:0},{t:15,v:.5,e:0},{t:20,v:1,e:0}],loop:false}}],portsOut:[{name:"Points",links:[{portIn:"Array 1",portOut:"Points",objIn:"d5604fc5-0353-40d6-8667-e251171ee20d",objOut:"29b4af3d-a32a-41d6-a22d-be0d72bdc099"},{portIn:"Array 2",portOut:"Points",objIn:"d5604fc5-0353-40d6-8667-e251171ee20d",objOut:"29b4af3d-a32a-41d6-a22d-be0d72bdc099"}]},{name:"Total points",value:6},{name:"Array lengths",value:18}],objName:"Ops.Extension.Deprecated.PointsCircle"},{id:"89b063b3-bb76-438e-a1a8-424a6678ef66",uiAttribs:{},portsIn:[{name:"use original size",value:1},{name:"width",value:641},{name:"height",value:400},{name:"filter index",value:1},{name:"filter",value:"linear"},{name:"wrap index",value:0},{name:"wrap",value:"clamp to edge"},{name:"HDR",value:1},{name:"Alpha Mask Source index",value:0},{name:"Alpha Mask Source",value:"A"},{name:"Convert Greyscale index",value:0},{name:"Convert Greyscale",value:"Off"},{name:"Invert R",value:0},{name:"Invert G",value:0},{name:"Invert B",value:0},{name:"Invert A",value:0}],portsOut:[{name:"texture_out",links:[{portIn:"Image",portOut:"texture_out",objIn:"7986ff15-d67f-45f7-bbbc-890e37165b31",objOut:"89b063b3-bb76-438e-a1a8-424a6678ef66"}]},{name:"Aspect Ratio",value:1.6025}],objName:"Ops.Gl.Textures.CopyTexture"},{id:"d5604fc5-0353-40d6-8667-e251171ee20d",uiAttribs:{},portsIn:[{name:"Chunk Size",value:1}],portsOut:[{name:"Combined Array",links:[{portIn:"Array 1",portOut:"Combined Array",objIn:"f98b78e0-5e83-4898-ad4a-d1ce1d1e61bb",objOut:"d5604fc5-0353-40d6-8667-e251171ee20d"},{portIn:"Array 2",portOut:"Combined Array",objIn:"f98b78e0-5e83-4898-ad4a-d1ce1d1e61bb",objOut:"d5604fc5-0353-40d6-8667-e251171ee20d"}]}],objName:"Ops.Array.WeaveArrays"},{id:"f98b78e0-5e83-4898-ad4a-d1ce1d1e61bb",uiAttribs:{},portsIn:[{name:"Chunk Size",value:.4}],portsOut:[{name:"Combined Array",links:[{portIn:"Points",portOut:"Combined Array",objIn:"7c1d6ad5-5b6e-4e41-989b-6ae46396a3bd",objOut:"f98b78e0-5e83-4898-ad4a-d1ce1d1e61bb"}]}],objName:"Ops.Array.WeaveArrays"},{id:"7c1d6ad5-5b6e-4e41-989b-6ae46396a3bd",uiAttribs:{},portsIn:[{name:"Axis 1 index",value:2},{name:"Axis 1",value:"Z"},{name:"Axis 2 index",value:0},{name:"Axis 2",value:"X"},{name:"Axis 3 index",value:2},{name:"Axis 3",value:"Z"},{name:"Flip Order X",value:1},{name:"Flip Order Y",value:1},{name:"Flip Order Z",value:0}],portsOut:[{name:"Result",links:[{portIn:"array",portOut:"Result",objIn:"795226ab-c9f5-491e-9c18-271f3fadd58b",objOut:"7c1d6ad5-5b6e-4e41-989b-6ae46396a3bd"},{portIn:"Array",portOut:"Result",objIn:"1ce4007d-e083-47a5-8ff4-3bcbaedb2d69",objOut:"7c1d6ad5-5b6e-4e41-989b-6ae46396a3bd"}]}],objName:"Ops.Extension.Deprecated.Array3FlipAxis"},{id:"2f51a87d-2b26-4c4f-974b-e691f4705696",uiAttribs:{},portsIn:[{name:"posX",value:0},{name:"posY",value:0},{name:"posZ",value:0},{name:"scale",value:1},{name:"rotX",value:0},{name:"rotY",value:0},{name:"rotZ",value:0}],portsOut:[{name:"trigger",links:[{portIn:"exe",portOut:"trigger",objIn:"795226ab-c9f5-491e-9c18-271f3fadd58b",objOut:"2f51a87d-2b26-4c4f-974b-e691f4705696"}]}],objName:"Ops.Gl.Matrix.Transform"},{id:"00e440e3-f5a3-4e93-be97-5fab29dd3d37",uiAttribs:{},portsIn:[{name:"Blend Mode index",value:0},{name:"Blend Mode",value:"normal"},{name:"Amount",value:1},{name:"Alpha Mask index",value:0},{name:"Alpha Mask",value:"Off"},{name:"Mask Invert",value:0},{name:"r",value:.6133333333333333},{name:"g",value:.1699544270833333},{name:"b",value:.5069223958333335},{name:"A",value:1}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"7986ff15-d67f-45f7-bbbc-890e37165b31",objOut:"00e440e3-f5a3-4e93-be97-5fab29dd3d37"}]}],objName:"Ops.Gl.ImageCompose.Color_v2"},{id:"4b830f72-a5bd-4391-842a-5fbed03a4274",uiAttribs:{},portsIn:[{name:"hue",value:0}],objName:"Ops.Gl.ImageCompose.Hue"},{id:"41985686-c6cf-42c2-a136-e965fec3df82",uiAttribs:{},portsIn:[{name:"Index",value:-107.96060730406246,animated:true,anim:{keys:[{t:0,v:-126,e:0},{t:4.3865999999999765,v:-90,e:0},{t:6.466666666666667,v:-90,e:0},{t:6.666666666666667,v:-7,e:0},{t:7,v:-7,e:0}],loop:false}}],portsOut:[{name:"Texture",links:[{portIn:"Alpha Mask",portOut:"Texture",objIn:"89b063b3-bb76-438e-a1a8-424a6678ef66",objOut:"41985686-c6cf-42c2-a136-e965fec3df82"},{portIn:"texture",portOut:"Texture",objIn:"20ef90b6-b959-49a4-987f-f64b421a9811",objOut:"41985686-c6cf-42c2-a136-e965fec3df82"}]}],objName:"Ops.Color.ColorPalettes"},{id:"20ef90b6-b959-49a4-987f-f64b421a9811",uiAttribs:{},portsIn:[{name:"r",value:.796078431372549},{name:"g",value:.2235294117647059},{name:"b",value:.2235294117647059},{name:"a",value:1},{name:"colorizeTexture",value:0},{name:"Vertex Colors",value:0},{name:"Alpha Mask Source index",value:0},{name:"Alpha Mask Source",value:"Luminance"},{name:"Opacity TexCoords Transform",value:0},{name:"Discard Transparent Pixels",value:0},{name:"diffuseRepeatX",value:1},{name:"diffuseRepeatY",value:1},{name:"Tex Offset X",value:0},{name:"Tex Offset Y",value:0},{name:"Crop TexCoords",value:0},{name:"billboard",value:0}],portsOut:[{name:"trigger",links:[{portIn:"Render",portOut:"trigger",objIn:"c9a4f300-9b50-4987-a1dd-f78ad4d1d5cb",objOut:"20ef90b6-b959-49a4-987f-f64b421a9811"}]}],objName:"Ops.Gl.Shader.BasicMaterial_v3"},{id:"f759fd56-11f1-44a6-846d-f2041194f2b4",uiAttribs:{},portsIn:[{name:"r",value:1},{name:"g",value:1},{name:"b",value:1},{name:"a",value:1},{name:"colorizeTexture",value:0},{name:"Vertex Colors",value:0},{name:"Alpha Mask Source index",value:0},{name:"Alpha Mask Source",value:"Luminance"},{name:"Opacity TexCoords Transform",value:0},{name:"Discard Transparent Pixels",value:0},{name:"diffuseRepeatX",value:1},{name:"diffuseRepeatY",value:1},{name:"Tex Offset X",value:0},{name:"Tex Offset Y",value:0},{name:"Crop TexCoords",value:0},{name:"billboard",value:0}],portsOut:[{name:"trigger",links:[{portIn:"Transform",portOut:"trigger",objIn:"1ce4007d-e083-47a5-8ff4-3bcbaedb2d69",objOut:"f759fd56-11f1-44a6-846d-f2041194f2b4"}]}],objName:"Ops.Gl.Shader.BasicMaterial_v3"},{id:"1ce4007d-e083-47a5-8ff4-3bcbaedb2d69",uiAttribs:{},portsIn:[{name:"Translate X",value:0},{name:"Translate Y",value:0},{name:"Translate Z",value:0},{name:"Scale X",value:10},{name:"Scale Y",value:10},{name:"Scale Z",value:10},{name:"Rotation X",value:0},{name:"Rotation Y",value:19.81592654424019,animated:true,anim:{keys:[{t:0,v:0,e:0},{t:39.93333333333333,v:360,e:12}],loop:false}},{name:"Rotation Z",value:0}],portsOut:[{name:"Next",links:[{portIn:"Render",portOut:"Next",objIn:"8852bbcd-c35f-473e-a3e8-f79804085937",objOut:"1ce4007d-e083-47a5-8ff4-3bcbaedb2d69"}]},{name:"Result",links:[{portIn:"Points",portOut:"Result",objIn:"8852bbcd-c35f-473e-a3e8-f79804085937",objOut:"1ce4007d-e083-47a5-8ff4-3bcbaedb2d69"}]}],objName:"Ops.Array.PointArray.TransformArray3"},{id:"1c046b36-7022-4ece-b7bd-b3f4d011a5cf",uiAttribs:{},portsIn:[{name:"blendMode index",value:0},{name:"blendMode",value:"normal"},{name:"amount",value:1},{name:"Premultiplied",value:0},{name:"Alpha Mask",value:0},{name:"removeAlphaSrc",value:0},{name:"Mask Src index",value:0},{name:"Mask Src",value:"alpha channel"},{name:"Invert alpha channel",value:0},{name:"Aspect Ratio",value:0},{name:"Stretch Axis index",value:0},{name:"Stretch Axis",value:"X"},{name:"Position",value:0},{name:"Crop",value:0},{name:"flip x",value:0},{name:"flip y",value:0},{name:"Transform",value:0},{name:"Scale X",value:1},{name:"Scale Y",value:1},{name:"Position X",value:0},{name:"Position Y",value:0},{name:"Rotation",value:0},{name:"Clip Repeat",value:0}],portsOut:[{name:"trigger",links:[{portIn:"render",portOut:"trigger",objIn:"f759fd56-11f1-44a6-846d-f2041194f2b4",objOut:"1c046b36-7022-4ece-b7bd-b3f4d011a5cf"}]}],objName:"Ops.Gl.ImageCompose.DrawImage_v3"},{id:"3d2ba1c4-b1b4-441c-a32e-f88c27fda4f0",uiAttribs:{},portsIn:[{name:"Size index",value:0},{name:"Size",value:"Auto"},{name:"Width",value:640},{name:"Height",value:480},{name:"Filter index",value:1},{name:"Filter",value:"linear"},{name:"Wrap index",value:1},{name:"Wrap",value:"repeat"},{name:"Pixel Format index",value:4},{name:"Pixel Format",value:"RGBA 8bit ubyte"},{name:"R",value:0},{name:"G",value:0},{name:"B",value:0},{name:"A",value:0}],portsOut:[{name:"Next",links:[{portIn:"render",portOut:"Next",objIn:"1c046b36-7022-4ece-b7bd-b3f4d011a5cf",objOut:"3d2ba1c4-b1b4-441c-a32e-f88c27fda4f0"}]},{name:"texture_out",links:[{portIn:"Image",portOut:"texture_out",objIn:"1c046b36-7022-4ece-b7bd-b3f4d011a5cf",objOut:"3d2ba1c4-b1b4-441c-a32e-f88c27fda4f0"}]},{name:"Aspect Ratio",value:1.6025},{name:"Texture Width",value:641},{name:"Texture Height",value:400}],objName:"Ops.Gl.ImageCompose.ImageCompose_v3"},{id:"8852bbcd-c35f-473e-a3e8-f79804085937",uiAttribs:{},portsIn:[{name:"Tesselate Edges",value:0},{name:"Render Mesh",value:1}],objName:"Ops.Gl.Meshes.SplineMesh_v2"},{id:"c9a4f300-9b50-4987-a1dd-f78ad4d1d5cb",uiAttribs:{},portsIn:[{name:"data",value:""},{name:"glb File",value:"assets/63963d1310384ae5707d78ed_Diamond2.glb",display:"file"},{name:"Draw",value:1},{name:"Camera index",value:0},{name:"Camera",value:"None"},{name:"Animation",value:""},{name:"Center index",value:1},{name:"Center",value:"XYZ"},{name:"Rescale",value:1},{name:"Rescale Size",value:.88},{name:"Time",value:0},{name:"Sync to timeline",value:0},{name:"Loop",value:1},{name:"Normals Format index",value:0},{name:"Normals Format",value:"XYZ"},{name:"Vertices Format index",value:0},{name:"Vertices Format",value:"XYZ"},{name:"Calc Normals",value:0},{name:"Hide Nodes",value:0},{name:"Use Material Properties",value:0},{name:"Active",value:1}],portsOut:[{name:"Generator",value:"Khronos glTF Blender I/O v3.6.27"},{name:"GLTF Version",value:2},{name:"Anim Length",value:0},{name:"Anim Time",value:0},{name:"Loading",value:false}],objName:"Ops.Gl.GLTF.GltfScene_v3"},{id:"51fb46b1-8a0c-4106-9793-62c5cfda9381",uiAttribs:{},portsIn:[{name:"r",value:1},{name:"g",value:.3960229492187497},{name:"b",value:0},{name:"Opacity",value:1},{name:"AO Intensity",value:1},{name:"Normal Map Intensity",value:1},{name:"Repeat X",value:1},{name:"Repeat Y",value:1},{name:"Offset X",value:0},{name:"Offset Y",value:0},{name:"Double Sided",value:0},{name:"Screen Space Normals",value:0},{name:"Calc normal tangents",value:1},{name:"Opacity TexCoords Transform",value:0},{name:"Discard Transparent Pixels",value:0},{name:"Alpha Mask Source index",value:0},{name:"Alpha Mask Source",value:"Luminance"}],portsOut:[{name:"Next",links:[{portIn:"Render",portOut:"Next",objIn:"c9a4f300-9b50-4987-a1dd-f78ad4d1d5cb",objOut:"51fb46b1-8a0c-4106-9793-62c5cfda9381"}]},{name:"Shader",links:[{portIn:"Materials",portOut:"Shader",objIn:"c9a4f300-9b50-4987-a1dd-f78ad4d1d5cb",objOut:"51fb46b1-8a0c-4106-9793-62c5cfda9381"}]}],objName:"Ops.Gl.Shader.MatCapMaterial_v3"},{id:"f40e58dc-2a1c-4a0e-8d1a-744a37a434f9",uiAttribs:{},portsIn:[{name:"File",value:"assets/lib_matcaps_Chrome_Bright_Blue_Tint_Black.png",display:"file"},{name:"Filter index",value:2},{name:"Filter",value:"mipmap"},{name:"Wrap index",value:0},{name:"Wrap",value:"repeat"},{name:"Anisotropic index",value:0},{name:"Anisotropic",value:0},{name:"Data Format index",value:3},{name:"Data Format",value:"RGBA"},{name:"Flip",value:0},{name:"Pre Multiplied Alpha",value:0},{name:"Active",value:1},{name:"Save Memory",value:1},{name:"Add Cachebuster",value:0}],portsOut:[{name:"Texture",links:[{portIn:"MatCap",portOut:"Texture",objIn:"51fb46b1-8a0c-4106-9793-62c5cfda9381",objOut:"f40e58dc-2a1c-4a0e-8d1a-744a37a434f9"}]},{name:"Width",value:256},{name:"Height",value:256},{name:"Aspect Ratio",value:1},{name:"Loaded",value:1},{name:"Loading",value:0}],objName:"Ops.Gl.Texture_v2"},{id:"1goyj4yg2",uiAttribs:{},portsIn:[{name:"Integer",value:2}],portsOut:[{name:"Number out",links:[{portIn:"Smooth",portOut:"Number out",objIn:"41985686-c6cf-42c2-a136-e965fec3df82",objOut:"1goyj4yg2"}]}],objName:"Ops.Number.Integer"},{id:"1dfceb7f-166f-4687-9f98-c44e51d44050",uiAttribs:{},portsIn:[{name:"File Type index",value:0},{name:"File Type",value:"PNG"},{name:"ZIP multiple files",value:1},{name:"Download Files",value:1},{name:"Filename",value:"cables11"},{name:"Quality",value:.8},{name:"Duration Type index",value:1},{name:"Duration Type",value:"Frames"},{name:"Duration",value:300},{name:"FPS",value:30},{name:"Transparency",value:0},{name:"Use Canvas Size",value:0},{name:"texture width",value:1920},{name:"texture height",value:1080}],portsOut:[{name:"Progress",value:0},{name:"Frame",value:0},{name:"Status",value:"Waiting"},{name:"Started",value:false}],objName:"Ops.Gl.RenderAnim_v2"},{id:"2c3831f3-3272-4d73-bf5e-f87904be7741",uiAttribs:{},portsIn:[{name:"Scale index",value:0},{name:"Scale",value:"Stretch"},{name:"Flip Y",value:0},{name:"Flip X",value:0}],portsOut:[{name:"trigger",links:[{portIn:"Render",portOut:"trigger",objIn:"1dfceb7f-166f-4687-9f98-c44e51d44050",objOut:"2c3831f3-3272-4d73-bf5e-f87904be7741"}]}],objName:"Ops.Gl.Meshes.FullscreenRectangle"},{id:"c0dy0qp1n",uiAttribs:{},portsIn:[{name:"In Min",value:0},{name:"Midpoint",value:.5,animated:true,anim:{keys:[{t:0,v:.5,e:0},{t:.9,v:.5,e:13},{t:1.4666666666666666,v:1,e:13},{t:1.7,v:.5,e:13},{t:6.4633000000000465,v:.5,e:13},{t:7.633333333333334,v:.86,e:13},{t:9.559800000000047,v:.5,e:0}],loop:false}},{name:"In Max",value:1},{name:"Out Min",value:0},{name:"Out Max",value:1}],objName:"Ops.Gl.ImageCompose.Levels_v2"},{id:"8jnd6b73b",uiAttribs:{},portsIn:[{name:"URL",value:"assets/ASMW25_demo_48kHz_16b.wav",display:"file"},{name:"Create Loading Task",value:1}],portsOut:[{name:"Audio Buffer",links:[{portIn:"Audio Buffer",portOut:"Audio Buffer",objIn:"h63p46tef",objOut:"8jnd6b73b"}]},{name:"Finished Loading",value:1},{name:"Sample Rate",value:48e3},{name:"Length",value:480152},{name:"Duration",value:10.003166666666667},{name:"Number of Channels",value:2},{name:"isLoading",value:false}],objName:"Ops.WebAudio.AudioBuffer_v2"},{id:"h63p46tef",uiAttribs:{},portsIn:[{name:"Offset",value:0},{name:"Playback Rate",value:1},{name:"Detune",value:0}],portsOut:[{name:"Audio Out",links:[{portIn:"Audio In",portOut:"Audio Out",objIn:"cdjfh81pp",objOut:"h63p46tef"}]},{name:"Is Playing",value:true},{name:"Loading",value:false}],objName:"Ops.WebAudio.AudioBufferPlayer_v2"},{id:"cdjfh81pp",uiAttribs:{},portsIn:[{name:"Volume",value:1},{name:"Mute",value:0},{name:"Show Audio Suspended Button",value:1}],portsOut:[{name:"Current Volume",value:1},{name:"Context State",value:"running"}],objName:"Ops.WebAudio.Output_v2"},{id:"6pqfcyujj",uiAttribs:{},portsOut:[{name:"Play/Stop",links:[{portIn:"Start / Stop",portOut:"Play/Stop",objIn:"h63p46tef",objOut:"6pqfcyujj"}]},{name:"time",links:[{portIn:"Loop",portOut:"time",objIn:"h63p46tef",objOut:"6pqfcyujj"}]}],objName:"Ops.TimeLine.TimeLineControls"}],export:{time:"2025-02-22 14:50",service:"exe",exportNumber:4}};if(!CABLES.exportedPatch){CABLES.exportedPatch=CABLES.exportedPatches["M2N0xD"]}"use strict";var CABLES=CABLES||{};CABLES.OPS=CABLES.OPS||{};var Ops=Ops||{};Ops.Gl=Ops.Gl||{};Ops.Array=Ops.Array||{};Ops.Color=Ops.Color||{};Ops.Number=Ops.Number||{};Ops.Gl.GLTF=Ops.Gl.GLTF||{};Ops.Trigger=Ops.Trigger||{};Ops.TimeLine=Ops.TimeLine||{};Ops.WebAudio=Ops.WebAudio||{};Ops.Extension=Ops.Extension||{};Ops.Gl.Matrix=Ops.Gl.Matrix||{};Ops.Gl.Meshes=Ops.Gl.Meshes||{};Ops.Gl.Shader=Ops.Gl.Shader||{};Ops.Gl.Textures=Ops.Gl.Textures||{};Ops.Gl.ImageCompose=Ops.Gl.ImageCompose||{};Ops.Array.PointArray=Ops.Array.PointArray||{};Ops.Extension.Deprecated=Ops.Extension.Deprecated||{};Ops.Gl.MainLoop=function(){CABLES.Op.apply(this,arguments);const i=this;const e=i.attachments={};const t=i.inValue("FPS Limit",0),n=i.outTrigger("trigger"),r=i.outNumber("width"),s=i.outNumber("height"),a=i.inValueBool("Reduce FPS not focussed",false),o=i.inValueBool("Reduce FPS loading"),l=i.inValueBool("Clear",true),h=i.inValueBool("ClearAlpha",true),u=i.inValueBool("Fullscreen Button",false),f=i.inValueBool("Active",true),c=i.inValueBool("Hires Displays",false),d=i.inSwitch("Pixel Unit",["Display","CSS"],"Display");i.onAnimFrame=y;c.onChange=function(){if(c.get())i.patch.cgl.pixelDensity=window.devicePixelRatio;else i.patch.cgl.pixelDensity=1;i.patch.cgl.updateSize();if(CABLES.UI)gui.setLayout()};f.onChange=function(){i.patch.removeOnAnimFrame(i);if(f.get()){i.setUiAttrib({extendTitle:""});i.onAnimFrame=y;i.patch.addOnAnimFrame(i);i.log("adding again!")}else{i.setUiAttrib({extendTitle:"Inactive"})}};const m=i.patch.cgl;let g=0;let p=0;let F=null;let A=false;if(!i.patch.cgl)i.uiAttr({error:"No webgl cgl context"});const C=vec3.create();vec3.set(C,0,0,0);const _=vec3.create();vec3.set(_,0,0,-2);u.onChange=D;setTimeout(D,100);let E=null;let v=true;let b=true;window.addEventListener("blur",()=>{v=false});window.addEventListener("focus",()=>{v=true});document.addEventListener("visibilitychange",()=>{b=!document.hidden});x();i.patch.tempData.mainloopOp=this;d.onChange=()=>{r.set(0);s.set(0)};function B(){if(o.get()&&i.patch.loading.getProgress()<1)return 5;if(a.get()){if(!b)return 10;if(!v)return 30}return t.get()}function D(){function e(){if(E)E.style.display="block"}function t(){if(E)E.style.display="none"}i.patch.cgl.canvas.addEventListener("mouseleave",t);i.patch.cgl.canvas.addEventListener("mouseenter",e);if(u.get()){if(!E){E=document.createElement("div");const n=i.patch.cgl.canvas.parentElement;if(n)n.appendChild(E);E.addEventListener("mouseenter",e);E.addEventListener("click",function(e){if(CABLES.UI&&!e.shiftKey)gui.cycleFullscreen();else m.fullScreen()})}E.style.padding="10px";E.style.position="absolute";E.style.right="5px";E.style.top="5px";E.style.width="20px";E.style.height="20px";E.style.cursor="pointer";E.style["border-radius"]="40px";E.style.background="#444";E.style["z-index"]="9999";E.style.display="none";E.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 490 490" style="width:20px;height:20px;" xml:space="preserve" width="512px" height="512px"><g><path d="M173.792,301.792L21.333,454.251v-80.917c0-5.891-4.776-10.667-10.667-10.667C4.776,362.667,0,367.442,0,373.333V480     c0,5.891,4.776,10.667,10.667,10.667h106.667c5.891,0,10.667-4.776,10.667-10.667s-4.776-10.667-10.667-10.667H36.416     l152.459-152.459c4.093-4.237,3.975-10.99-0.262-15.083C184.479,297.799,177.926,297.799,173.792,301.792z" fill="#FFFFFF"/><path d="M480,0H373.333c-5.891,0-10.667,4.776-10.667,10.667c0,5.891,4.776,10.667,10.667,10.667h80.917L301.792,173.792     c-4.237,4.093-4.354,10.845-0.262,15.083c4.093,4.237,10.845,4.354,15.083,0.262c0.089-0.086,0.176-0.173,0.262-0.262     L469.333,36.416v80.917c0,5.891,4.776,10.667,10.667,10.667s10.667-4.776,10.667-10.667V10.667C490.667,4.776,485.891,0,480,0z" fill="#FFFFFF"/><path d="M36.416,21.333h80.917c5.891,0,10.667-4.776,10.667-10.667C128,4.776,123.224,0,117.333,0H10.667     C4.776,0,0,4.776,0,10.667v106.667C0,123.224,4.776,128,10.667,128c5.891,0,10.667-4.776,10.667-10.667V36.416l152.459,152.459     c4.237,4.093,10.99,3.975,15.083-0.262c3.992-4.134,3.992-10.687,0-14.82L36.416,21.333z" fill="#FFFFFF"/><path d="M480,362.667c-5.891,0-10.667,4.776-10.667,10.667v80.917L316.875,301.792c-4.237-4.093-10.99-3.976-15.083,0.261     c-3.993,4.134-3.993,10.688,0,14.821l152.459,152.459h-80.917c-5.891,0-10.667,4.776-10.667,10.667s4.776,10.667,10.667,10.667     H480c5.891,0,10.667-4.776,10.667-10.667V373.333C490.667,367.442,485.891,362.667,480,362.667z" fill="#FFFFFF"/></g></svg>'}else{if(E){E.style.display="none";E.remove();E=null}}}i.onDelete=function(){m.gl.clearColor(0,0,0,0);m.gl.clear(m.gl.COLOR_BUFFER_BIT|m.gl.DEPTH_BUFFER_BIT)};function y(e){if(!f.get())return;if(m.aborted||m.canvas.clientWidth===0||m.canvas.clientHeight===0)return;i.patch.cg=m;if(c.get())i.patch.cgl.pixelDensity=window.devicePixelRatio;const t=performance.now();i.patch.config.fpsLimit=B();if(m.canvasWidth==-1){m.setCanvas(i.patch.config.glCanvasId);return}if(m.canvasWidth!=r.get()||m.canvasHeight!=s.get()){let e=1;if(d.get()=="CSS")e=i.patch.cgl.pixelDensity;r.set(m.canvasWidth/e);s.set(m.canvasHeight/e)}if(CABLES.now()-p>1e3){CGL.fpsReport=CGL.fpsReport||[];if(i.patch.loading.getProgress()>=1&&p!==0)CGL.fpsReport.push(g);g=0;p=CABLES.now()}CGL.MESH.lastShader=null;CGL.MESH.lastMesh=null;m.renderStart(m,C,_);if(l.get()){m.gl.clearColor(0,0,0,1);m.gl.clear(m.gl.COLOR_BUFFER_BIT|m.gl.DEPTH_BUFFER_BIT)}n.trigger();if(CGL.MESH.lastMesh)CGL.MESH.lastMesh.unBind();if(CGL.Texture.previewTexture){if(!CGL.Texture.texturePreviewer)CGL.Texture.texturePreviewer=new CGL.Texture.texturePreview(m);CGL.Texture.texturePreviewer.render(CGL.Texture.previewTexture)}m.renderEnd(m);i.patch.cg=null;if(h.get()){m.gl.clearColor(1,1,1,1);m.gl.colorMask(false,false,false,true);m.gl.clear(m.gl.COLOR_BUFFER_BIT);m.gl.colorMask(true,true,true,true)}if(!m.tempData.phong)m.tempData.phong={};g++;i.patch.cgl.profileData.profileMainloopMs=performance.now()-t}function x(){clearTimeout(F);F=setTimeout(()=>{if(i.patch.getOpsByObjName(i.name).length>1){i.setUiError("multimainloop","there should only be one mainloop op!");if(!A)A=i.patch.addEventListener("onOpDelete",x)}else i.setUiError("multimainloop",null,1)},500)}};Ops.Gl.MainLoop.prototype=new CABLES.Op;CABLES.OPS["b0472a1d-db16-4ba6-8787-f300fbdc77bb"]={f:Ops.Gl.MainLoop,objName:"Ops.Gl.MainLoop"};Ops.TimeLine.TimeLineLoop=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inTrigger("Execute"),i=e.inValueFloat("duration",2),r=e.outTrigger("trigger");n.onTriggered=function(){if(e.patch.timer.getTime()>i.get())e.patch.timer.setTime(0);r.trigger()}};Ops.TimeLine.TimeLineLoop.prototype=new CABLES.Op;CABLES.OPS["e450a850-7311-48b5-abfc-07ec1fea3b8e"]={f:Ops.TimeLine.TimeLineLoop,objName:"Ops.TimeLine.TimeLineLoop"};Ops.Trigger.Sequence=function(){CABLES.Op.apply(this,arguments);const s=this;const e=s.attachments={};const t=s.inTrigger("exe"),n=s.inTriggerButton("Clean up connections");s.setUiAttrib({resizable:true,resizableY:false,stretchPorts:true});const i=[],a=[],r=16;let o=null,l=[];t.onTriggered=f;n.onTriggered=c;n.setUiAttribs({hideParam:true,hidePort:true});for(let t=0;t<r;t++){const d=s.outTrigger("trigger "+t);a.push(d);d.onLinkChanged=u;if(t<r-1){let e=s.inTrigger("exe "+t);e.onTriggered=f;i.push(e)}}h();function h(){l.length=0;for(let e=0;e<a.length;e++)if(a[e].links.length>0)l.push(a[e])}function u(){h();clearTimeout(o);o=setTimeout(()=>{let t=false;for(let e=0;e<a.length;e++)if(a[e].links.length>1)t=true;n.setUiAttribs({hideParam:!t});if(s.isCurrentUiOp())s.refreshParams()},60)}function f(){for(let e=0;e<l.length;e++)l[e].trigger()}function c(){let i=0;for(let n=0;n<a.length;n++){let t=[];if(a[n].links.length>1)for(let e=1;e<a[n].links.length;e++){while(a[i].links.length>0)i++;t.push(a[n].links[e]);const r=a[n].links[e].getOtherPort(a[n]);s.patch.link(s,"trigger "+i,r.op,r.name);i++}for(let e=0;e<t.length;e++)t[e].remove()}u();h()}};Ops.Trigger.Sequence.prototype=new CABLES.Op;CABLES.OPS["a466bc1f-06e9-4595-8849-bffb9fe22f99"]={f:Ops.Trigger.Sequence,objName:"Ops.Trigger.Sequence"};Ops.Gl.ImageCompose.ImageCompose_v3=function(){CABLES.Op.apply(this,arguments);const n=this;const e=n.attachments={imgcomp_frag:"IN vec2 texCoord;\nUNI vec4 bgColor;\nUNI sampler2D tex;\n#ifdef USE_UVTEX\nUNI sampler2D UVTex;\n#endif\n\nvoid main()\n{\n\n    #ifndef USE_TEX\n        outColor=bgColor;\n    #endif\n    #ifdef USE_TEX\n        #ifndef USE_UVTEX\n        outColor=texture(tex,texCoord);\n        #else\n        outColor=texture(tex,texture(UVTex,texCoord).xy);\n        #endif\n    #endif\n\n\n\n}\n"};const i=n.patch.cgl,t=n.inTrigger("Render"),r=n.inTexture("Base Texture"),s=n.inTexture("UV Texture"),a=n.inSwitch("Size",["Auto","Manual"],"Auto"),o=n.inValueInt("Width",640),l=n.inValueInt("Height",480),h=n.inSwitch("Filter",["nearest","linear","mipmap"],"linear"),u=n.inValueSelect("Wrap",["clamp to edge","repeat","mirrored repeat"],"repeat"),f=n.inDropDown("Pixel Format",CGL.Texture.PIXELFORMATS,CGL.Texture.PFORMATSTR_RGBA8UB),c=n.inValueSlider("R",0),d=n.inValueSlider("G",0),m=n.inValueSlider("B",0),g=n.inValueSlider("A",0),p=n.outTrigger("Next"),F=n.outTexture("texture_out",CGL.Texture.getEmptyTexture(i)),A=n.outNumber("Aspect Ratio"),C=n.outNumber("Texture Width"),R=n.outNumber("Texture Height");n.setPortGroup("Texture Size",[a,o,l]);n.setPortGroup("Texture Parameters",[u,h,f]);c.setUiAttribs({colorPick:true});n.setPortGroup("Color",[c,d,m,g]);n.toWorkPortsNeedToBeLinked(t);const _=[0,0,0,0];let E=null;let v=null;let b=true;let k=false;let B=null;let M=null;let P=null;let U=null;u.onChange=h.onChange=f.onChange=V;r.onLinkChanged=a.onChange=s.onChange=w;t.onTriggered=n.preRender=N;w();function D(){if(E)E.delete();if(v)v.delete();E=new CGL.TextureEffect(i,{isFloatingPointTexture:CGL.Texture.isPixelFormatFloat(f.get())});v=new CGL.Texture(i,{name:"image_compose_v2_"+n.id,isFloatingPointTexture:CGL.Texture.isPixelFormatFloat(f.get()),pixelFormat:f.get(),filter:y(),wrap:x(),width:S(),height:T()});E.setSourceTexture(v);C.set(S());R.set(T());A.set(S()/T());F.set(CGL.Texture.getEmptyTexture(i));b=false;w()}function y(){if(h.get()=="nearest")return CGL.Texture.FILTER_NEAREST;else if(h.get()=="linear")return CGL.Texture.FILTER_LINEAR;else if(h.get()=="mipmap")return CGL.Texture.FILTER_MIPMAP}function x(){if(u.get()=="repeat")return CGL.Texture.WRAP_REPEAT;else if(u.get()=="mirrored repeat")return CGL.Texture.WRAP_MIRRORED_REPEAT;else if(u.get()=="clamp to edge")return CGL.Texture.WRAP_CLAMP_TO_EDGE}function S(){if(r.get()&&a.get()=="Auto")return r.get().width;if(a.get()=="Auto")return i.getViewPort()[2];return Math.ceil(o.get())}function T(){if(r.get()&&a.get()=="Auto")return r.get().height;else if(a.get()=="Auto")return i.getViewPort()[3];else return Math.ceil(l.get())}function V(){b=true}function G(){if((S()!=v.width||T()!=v.height||v.pixelFormat!=f.get()||v.filter!=y()||v.wrap!=x())&&(S()!==0&&T()!==0)){D();E.setSourceTexture(v);F.set(CGL.Texture.getEmptyTexture(i));F.set(v);O();L()}}function O(){let e=null;if(a.get()=="Manual"){e=null}else if(a.get()=="Auto"){if(r.get())e="Input Texture";else e="Canvas Size";e+=": "+S()+" x "+T()}let t=false;t=a.uiAttribs.info!=e;a.setUiAttribs({info:e});if(t)n.refreshParams()}function I(){if(B)B.toggleDefine("USE_TEX",r.isLinked());if(B)B.toggleDefine("USE_UVTEX",s.isLinked())}function w(){c.setUiAttribs({greyout:r.isLinked()});m.setUiAttribs({greyout:r.isLinked()});d.setUiAttribs({greyout:r.isLinked()});g.setUiAttribs({greyout:r.isLinked()});o.setUiAttribs({greyout:a.get()=="Auto"});l.setUiAttribs({greyout:a.get()=="Auto"});o.setUiAttribs({hideParam:a.get()!="Manual"});l.setUiAttribs({hideParam:a.get()!="Manual"});if(v)if(CGL.Texture.isPixelFormatFloat(f.get())&&y()==CGL.Texture.FILTER_MIPMAP)n.setUiError("fpmipmap","Don't use mipmap and 32bit at the same time, many systems do not support this.");else n.setUiError("fpmipmap",null);O();I();L()}function L(){if(v)if(r.isLinked()&&r.get()&&v.textureType!=r.get().textureType&&(v.textureType!=CGL.Texture.TYPE_FLOAT||r.get().textureType==CGL.Texture.TYPE_FLOAT))n.setUiError("textypediff","Drawing 32bit texture into an 8 bit can result in data/precision loss",1);else n.setUiError("textypediff",null)}n.preRender=()=>{N()};function j(){if(!B){B=new CGL.Shader(i,"copytextureshader");B.setSource(B.getDefaultVertexShader(),e.imgcomp_frag);M=new CGL.Uniform(B,"t","tex",0);P=new CGL.Uniform(B,"t","UVTex",1);U=new CGL.Uniform(B,"4f","bgColor",c,d,m,g);I()}i.pushShader(B);i.currentTextureEffect.bind();if(r.get())i.setTexture(0,r.get().tex);if(s.get())i.setTexture(1,s.get().tex);i.currentTextureEffect.finish();i.popShader()}function N(){if(!E||b)D();const e=i.getViewPort();_[0]=e[0];_[1]=e[1];_[2]=e[2];_[3]=e[3];i.pushBlend(false);G();const t=i.currentTextureEffect;i.currentTextureEffect=E;i.currentTextureEffect.imgCompVer=3;i.currentTextureEffect.width=o.get();i.currentTextureEffect.height=l.get();E.setSourceTexture(v);E.startEffect(r.get()||CGL.Texture.getEmptyTexture(i,k),true);j();p.trigger();F.setRef(E.getCurrentSourceTexture());E.endEffect();i.setViewPort(_[0],_[1],_[2],_[3]);i.popBlend(false);i.currentTextureEffect=t}};Ops.Gl.ImageCompose.ImageCompose_v3.prototype=new CABLES.Op;CABLES.OPS["e890a050-11b7-456e-b09b-d08cd9c1ee41"]={f:Ops.Gl.ImageCompose.ImageCompose_v3,objName:"Ops.Gl.ImageCompose.ImageCompose_v3"};Ops.Gl.ImageCompose.DrawImage_v3=function(){CABLES.Op.apply(this,arguments);const i=this;const e=i.attachments={drawimage_frag:"#ifdef HAS_TEXTURES\n    IN vec2 texCoord;\n    UNI sampler2D tex;\n    UNI sampler2D image;\n#endif\n\n#ifdef TEX_TRANSFORM\n    IN mat3 transform;\n#endif\n// UNI float rotate;\n\n{{CGL.BLENDMODES}}\n\n#ifdef HAS_TEXTUREALPHA\n   UNI sampler2D imageAlpha;\n#endif\n\nUNI float amount;\n\n#ifdef ASPECT_RATIO\n    UNI float aspectTex;\n    UNI float aspectPos;\n#endif\n\nvoid main()\n{\n    vec4 blendRGBA=vec4(0.0,0.0,0.0,1.0);\n\n    #ifdef HAS_TEXTURES\n        vec2 tc=texCoord;\n\n        #ifdef TEX_FLIP_X\n            tc.x=1.0-tc.x;\n        #endif\n        #ifdef TEX_FLIP_Y\n            tc.y=1.0-tc.y;\n        #endif\n\n        #ifdef ASPECT_RATIO\n            #ifdef ASPECT_AXIS_X\n                tc.y=(1.0-aspectPos)-(((1.0-aspectPos)-tc.y)*aspectTex);\n            #endif\n            #ifdef ASPECT_AXIS_Y\n                tc.x=(1.0-aspectPos)-(((1.0-aspectPos)-tc.x)/aspectTex);\n            #endif\n        #endif\n\n        #ifdef TEX_TRANSFORM\n            vec3 coordinates=vec3(tc.x, tc.y,1.0);\n            tc=(transform * coordinates ).xy;\n        #endif\n\n        blendRGBA=texture(image,tc);\n\n        vec3 blend=blendRGBA.rgb;\n        vec4 baseRGBA=texture(tex,texCoord);\n        vec3 base=baseRGBA.rgb;\n\n\n        #ifdef PREMUL\n            blend.rgb = (blend.rgb) + (base.rgb * (1.0 - blendRGBA.a));\n        #endif\n\n        vec3 colNew=_blend(base,blend);\n\n\n\n\n        #ifdef REMOVE_ALPHA_SRC\n            blendRGBA.a=1.0;\n        #endif\n\n        #ifdef HAS_TEXTUREALPHA\n            vec4 colImgAlpha=texture(imageAlpha,tc);\n            float colImgAlphaAlpha=colImgAlpha.a;\n\n            #ifdef ALPHA_FROM_LUMINANCE\n                vec3 gray = vec3(dot(vec3(0.2126,0.7152,0.0722), colImgAlpha.rgb ));\n                colImgAlphaAlpha=(gray.r+gray.g+gray.b)/3.0;\n            #endif\n\n            #ifdef ALPHA_FROM_INV_UMINANCE\n                vec3 gray = vec3(dot(vec3(0.2126,0.7152,0.0722), colImgAlpha.rgb ));\n                colImgAlphaAlpha=1.0-(gray.r+gray.g+gray.b)/3.0;\n            #endif\n\n            #ifdef INVERT_ALPHA\n                colImgAlphaAlpha=clamp(colImgAlphaAlpha,0.0,1.0);\n                colImgAlphaAlpha=1.0-colImgAlphaAlpha;\n            #endif\n\n            blendRGBA.a=colImgAlphaAlpha*blendRGBA.a;\n        #endif\n    #endif\n\n    float am=amount;\n\n    #ifdef CLIP_REPEAT\n        if(tc.y>1.0 || tc.y<0.0 || tc.x>1.0 || tc.x<0.0)\n        {\n            // colNew.rgb=vec3(0.0);\n            am=0.0;\n        }\n    #endif\n\n    #ifdef ASPECT_RATIO\n        #ifdef ASPECT_CROP\n            if(tc.y>1.0 || tc.y<0.0 || tc.x>1.0 || tc.x<0.0)\n            {\n                colNew.rgb=base.rgb;\n                am=0.0;\n            }\n\n        #endif\n    #endif\n\n\n\n    #ifndef PREMUL\n        blendRGBA.rgb=mix(colNew,base,1.0-(am*blendRGBA.a));\n        blendRGBA.a=clamp(baseRGBA.a+(blendRGBA.a*am),0.,1.);\n    #endif\n\n    #ifdef PREMUL\n        // premultiply\n        // blendRGBA.rgb = (blendRGBA.rgb) + (baseRGBA.rgb * (1.0 - blendRGBA.a));\n        blendRGBA=vec4(\n            mix(colNew.rgb,base,1.0-(am*blendRGBA.a)),\n            blendRGBA.a*am+baseRGBA.a\n            );\n    #endif\n\n    #ifdef ALPHA_MASK\n    blendRGBA.a=baseRGBA.a;\n    #endif\n\n    outColor=blendRGBA;\n}\n\n\n\n\n\n\n\n",drawimage_vert:"IN vec3 vPosition;\nIN vec2 attrTexCoord;\nIN vec3 attrVertNormal;\n\nUNI mat4 projMatrix;\nUNI mat4 mvMatrix;\n\nOUT vec2 texCoord;\n// OUT vec3 norm;\n\n#ifdef TEX_TRANSFORM\n    UNI float posX;\n    UNI float posY;\n    UNI float scaleX;\n    UNI float scaleY;\n    UNI float rotate;\n    OUT mat3 transform;\n#endif\n\nvoid main()\n{\n   texCoord=attrTexCoord;\n//   norm=attrVertNormal;\n\n   #ifdef TEX_TRANSFORM\n        vec3 coordinates=vec3(attrTexCoord.x, attrTexCoord.y,1.0);\n        float angle = radians( rotate );\n        vec2 scale= vec2(scaleX,scaleY);\n        vec2 translate= vec2(posX,posY);\n\n        transform = mat3(   scale.x * cos( angle ), scale.x * sin( angle ), 0.0,\n            - scale.y * sin( angle ), scale.y * cos( angle ), 0.0,\n            - 0.5 * scale.x * cos( angle ) + 0.5 * scale.y * sin( angle ) - 0.5 * translate.x*2.0 + 0.5,  - 0.5 * scale.x * sin( angle ) - 0.5 * scale.y * cos( angle ) - 0.5 * translate.y*2.0 + 0.5, 1.0);\n   #endif\n\n   gl_Position = projMatrix * mvMatrix * vec4(vPosition,  1.0);\n}\n"};const t=i.inTrigger("render"),n=CGL.TextureEffect.AddBlendSelect(i,"blendMode"),r=i.inValueSlider("amount",1),s=i.inTexture("Image"),a=i.inValueBool("Premultiplied",false),o=i.inValueBool("Alpha Mask",false),l=i.inValueBool("removeAlphaSrc",false),h=i.inTexture("Mask"),u=i.inValueSelect("Mask Src",["alpha channel","luminance","luminance inv"],"luminance"),f=i.inValueBool("Invert alpha channel"),c=i.inValueBool("Aspect Ratio",false),d=i.inValueSelect("Stretch Axis",["X","Y"],"X"),m=i.inValueSlider("Position",0),g=i.inValueBool("Crop",false),p=i.outTrigger("trigger");n.set("normal");const F=i.patch.cgl;const A=new CGL.Shader(F,"drawimage");h.onLinkChanged=C;i.setPortGroup("Mask",[h,u,f]);i.setPortGroup("Aspect Ratio",[c,m,g,d]);function C(){if(h.isLinked()){l.setUiAttribs({greyout:true});u.setUiAttribs({greyout:false});f.setUiAttribs({greyout:false})}else{l.setUiAttribs({greyout:false});u.setUiAttribs({greyout:true});f.setUiAttribs({greyout:true})}}i.toWorkPortsNeedToBeLinked(s);A.setSource(e.drawimage_vert,e.drawimage_frag);const _=new CGL.Uniform(A,"t","tex",0),R=new CGL.Uniform(A,"t","image",1),k=new CGL.Uniform(A,"t","imageAlpha",2),E=new CGL.Uniform(A,"f","aspectTex",1),M=new CGL.Uniform(A,"f","aspectPos",m);c.onChange=g.onChange=d.onChange=v;function v(){A.removeDefine("ASPECT_AXIS_X");A.removeDefine("ASPECT_AXIS_Y");A.removeDefine("ASPECT_CROP");m.setUiAttribs({greyout:!c.get()});g.setUiAttribs({greyout:!c.get()});d.setUiAttribs({greyout:!c.get()});if(c.get()){A.define("ASPECT_RATIO");if(g.get())A.define("ASPECT_CROP");if(d.get()=="X")A.define("ASPECT_AXIS_X");if(d.get()=="Y")A.define("ASPECT_AXIS_Y")}else{A.removeDefine("ASPECT_RATIO");if(g.get())A.define("ASPECT_CROP");if(d.get()=="X")A.define("ASPECT_AXIS_X");if(d.get()=="Y")A.define("ASPECT_AXIS_Y")}}const b=i.inValueBool("flip x");const B=i.inValueBool("flip y");let D=i.inValueBool("Transform");let y=i.inValueSlider("Scale X",1);let x=i.inValueSlider("Scale Y",1);let S=i.inValue("Position X",0);let T=i.inValue("Position Y",0);let O=i.inValue("Rotation",0);const I=i.inValueBool("Clip Repeat",false);const P=new CGL.Uniform(A,"f","scaleX",y);const U=new CGL.Uniform(A,"f","scaleY",x);const V=new CGL.Uniform(A,"f","posX",S);const G=new CGL.Uniform(A,"f","posY",T);const j=new CGL.Uniform(A,"f","rotate",O);D.onChange=w;function w(){A.toggleDefine("TEX_TRANSFORM",D.get());y.setUiAttribs({greyout:!D.get()});x.setUiAttribs({greyout:!D.get()});S.setUiAttribs({greyout:!D.get()});T.setUiAttribs({greyout:!D.get()});O.setUiAttribs({greyout:!D.get()})}CGL.TextureEffect.setupBlending(i,A,n,r);const z=new CGL.Uniform(A,"f","amount",r);t.onTriggered=N;I.onChange=h.onChange=a.onChange=o.onChange=f.onChange=B.onChange=b.onChange=l.onChange=u.onChange=L;w();C();v();L();function L(){A.toggleDefine("REMOVE_ALPHA_SRC",l.get());A.toggleDefine("ALPHA_MASK",o.get());A.toggleDefine("CLIP_REPEAT",I.get());A.toggleDefine("HAS_TEXTUREALPHA",h.get()&&h.get().tex);A.toggleDefine("TEX_FLIP_X",b.get());A.toggleDefine("TEX_FLIP_Y",B.get());A.toggleDefine("INVERT_ALPHA",f.get());A.toggleDefine("ALPHA_FROM_LUMINANCE",u.get()=="luminance");A.toggleDefine("ALPHA_FROM_INV_UMINANCE",u.get()=="luminance_inv");A.toggleDefine("PREMUL",a.get())}function N(){if(!CGL.TextureEffect.checkOpInEffect(i))return;const e=s.get();if(e&&e.tex&&r.get()>0){F.pushShader(A);F.currentTextureEffect.bind();const t=F.currentTextureEffect.getCurrentSourceTexture();F.setTexture(0,t.tex);const n=1/(F.currentTextureEffect.getWidth()/F.currentTextureEffect.getHeight())*(e.width/e.height);E.setValue(n);F.setTexture(1,e.tex);if(h.get()&&h.get().tex){F.setTexture(2,h.get().tex)}F.pushBlendMode(CGL.BLEND_NONE,true);F.currentTextureEffect.finish();F.popBlendMode();F.popShader()}p.trigger()}};Ops.Gl.ImageCompose.DrawImage_v3.prototype=new CABLES.Op;CABLES.OPS["8f6b2f15-fcb0-4597-90c0-e5173f2969fe"]={f:Ops.Gl.ImageCompose.DrawImage_v3,objName:"Ops.Gl.ImageCompose.DrawImage_v3"};Ops.Gl.RenderToTexture=function(){CABLES.Op.apply(this,arguments);const r=this;const e=r.attachments={};const s=r.patch.cgl;const t=r.inTrigger("render"),n=r.inValueBool("use viewport size",true),i=r.inValueInt("texture width",512),a=r.inValueInt("texture height",512),o=r.inBool("Auto Aspect",false),l=r.inSwitch("filter",["nearest","linear","mipmap"],"linear"),h=r.inSwitch("Wrap",["Clamp","Repeat","Mirror"],"Repeat"),u=r.inSwitch("MSAA",["none","2x","4x","8x"],"none"),f=r.outTrigger("trigger"),c=r.outTexture("texture"),d=r.outTexture("textureDepth"),m=r.inValueBool("HDR"),g=r.inValueBool("Depth",true),p=r.inValueBool("Clear",true);let F=null;let A=true;c.set(CGL.Texture.getEmptyTexture(s));r.setPortGroup("Size",[n,i,a,o]);const C=[0,0,0,0];m.setUiAttribs({title:"Pixelformat Float 32bit"});m.onChange=g.onChange=p.onChange=l.onChange=h.onChange=u.onChange=E;n.onChange=_;t.onTriggered=r.preRender=v;_();function _(){i.setUiAttribs({greyout:n.get()});a.setUiAttribs({greyout:n.get()});o.setUiAttribs({greyout:n.get()})}function E(){A=true}function v(){const e=s.getViewPort();C[0]=e[0];C[1]=e[1];C[2]=e[2];C[3]=e[3];if(!F||A){if(F)F.delete();let n=CGL.Texture.WRAP_REPEAT;if(h.get()=="Clamp")n=CGL.Texture.WRAP_CLAMP_TO_EDGE;else if(h.get()=="Mirror")n=CGL.Texture.WRAP_MIRRORED_REPEAT;let i=CGL.Texture.FILTER_NEAREST;if(l.get()=="nearest")i=CGL.Texture.FILTER_NEAREST;else if(l.get()=="linear")i=CGL.Texture.FILTER_LINEAR;else if(l.get()=="mipmap")i=CGL.Texture.FILTER_MIPMAP;if(m.get()&&l.get()=="mipmap")r.setUiError("fpmipmap","Don't use mipmap and HDR at the same time, many systems do not support this.");else r.setUiError("fpmipmap",null);if(s.glVersion>=2){let e=true;let t=4;if(u.get()=="none"){t=0;e=false}if(u.get()=="2x")t=2;if(u.get()=="4x")t=4;if(u.get()=="8x")t=8;F=new CGL.Framebuffer2(s,8,8,{name:"render2texture "+r.id,isFloatingPointTexture:m.get(),multisampling:e,wrap:n,filter:i,depth:g.get(),multisamplingSamples:t,clear:p.get()})}else{F=new CGL.Framebuffer(s,8,8,{isFloatingPointTexture:m.get(),clear:p.get()});console.log("WEBGL1!!!",F,F.valid)}if(F&&F.valid){d.set(F.getTextureDepth());A=false}else{F=null;A=true}}if(n.get()){i.set(s.getViewPort()[2]);a.set(s.getViewPort()[3])}if(F.getWidth()!=Math.ceil(i.get())||F.getHeight()!=Math.ceil(a.get())){F.setSize(Math.max(1,Math.ceil(i.get())),Math.max(1,Math.ceil(a.get())))}F.renderStart(s);if(o.get())mat4.perspective(s.pMatrix,45,i.get()/a.get(),.1,1e3);f.trigger();F.renderEnd(s);s.setViewPort(C[0],C[1],C[2],C[3]);d.setRef(F.getTextureDepth());c.setRef(F.getTextureColor())}};Ops.Gl.RenderToTexture.prototype=new CABLES.Op;CABLES.OPS["d01fa820-396c-4cb5-9d78-6b14762852af"]={f:Ops.Gl.RenderToTexture,objName:"Ops.Gl.RenderToTexture"};Ops.Gl.Matrix.ArrayPathFollow=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inTrigger("exe");const r=e.inArray("array");const i=e.inValueFloat("time");const s=e.inValueFloat("duration");s.set(.1);const a=e.inValueFloat("offset");a.set(0);const o=e.inValueFloat("look ahead");o.set(3);const l=e.outTrigger("trigger");const h=e.outTrigger("transform lookat");const u=e.addOutPort(new CABLES.Port(e,"index"));const f=vec3.create();const c=vec3.create();const d=e.patch.cgl;const m=CABLES.now();let g=new CABLES.Anim;let p=new CABLES.Anim;let F=new CABLES.Anim;let A=new CABLES.Anim;let C=new CABLES.Anim;let _=new CABLES.Anim;let E=new CABLES.Anim;let v=0;let b=.1;function B(){g=new CABLES.Anim;p=new CABLES.Anim;F=new CABLES.Anim;A=new CABLES.Anim;C=new CABLES.Anim;_=new CABLES.Anim;E=new CABLES.Anim;let e=0;const t=r.get();if(!t)return;b=parseFloat(s.get());for(e=0;e<t.length;e+=3){g.setValue(e/3*b,t[e+0]);p.setValue(e/3*b,t[e+1]);F.setValue(e/3*b,t[e+2]);v=e/3*b}for(e=0;e<t.length/3;e++){const n=e*b;const i=(e*b+b)%v;vec3.set(f,g.getValue(n),p.getValue(n),F.getValue(n));vec3.set(c,g.getValue(i),p.getValue(i),F.getValue(i));vec3.set(f,c[0]-f[0],c[1]-f[1],c[2]-f[2]);vec3.normalize(f,f);vec3.set(c,0,0,1);quat.rotationTo(D,c,f);A.setValue(e*b,D[0]);C.setValue(e*b,D[1]);_.setValue(e*b,D[2]);E.setValue(e*b,D[3])}}r.onChange=s.onChange=B;let D=quat.create();const y=mat4.create();function x(){if(!r.get())return;const e=(i.get()+parseFloat(a.get()))%v;const t=(i.get()+b*o.get()+parseFloat(a.get()))%v;vec3.set(f,g.getValue(e),p.getValue(e),F.getValue(e));u.set(t);if(h.isLinked()){vec3.set(c,g.getValue(t),p.getValue(t),F.getValue(t));d.pushModelMatrix();mat4.translate(d.mMatrix,d.mMatrix,c);h.trigger();d.popModelMatrix()}d.pushModelMatrix();mat4.translate(d.mMatrix,d.mMatrix,f);CABLES.Anim.slerpQuaternion(e,D,A,C,_,E);mat4.fromQuat(y,D);mat4.multiply(d.mMatrix,d.mMatrix,y);l.trigger();d.popModelMatrix()}n.onTriggered=x};Ops.Gl.Matrix.ArrayPathFollow.prototype=new CABLES.Op;CABLES.OPS["395bff14-d092-4e7e-a723-b6a69564add2"]={f:Ops.Gl.Matrix.ArrayPathFollow,objName:"Ops.Gl.Matrix.ArrayPathFollow"};Ops.Extension.Deprecated.PointsCircle=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.outArray("Points",3),a=e.inValueSlider("percent",1),i=e.inValue("segments",40),o=e.inValue("radius",1),l=e.outNumber("Total points"),h=e.outNumber("Array lengths");o.onChange=a.onChange=i.onChange=r;function r(){const r=Math.max(3,Math.floor(i.get()));const s=[];let e=0;for(let i=0;i<r*a.get();i++){let e=360/r*i*CGL.DEG2RAD;let t=Math.cos(e)*o.get();let n=Math.sin(e)*o.get();s.push(t);s.push(n);s.push(0)}n.setRef(s);l.set(s.length/3);h.set(s.length)}r()};Ops.Extension.Deprecated.PointsCircle.prototype=new CABLES.Op;CABLES.OPS["ef54ba67-8b1d-41b0-8140-bb97061eaa97"]={f:Ops.Extension.Deprecated.PointsCircle,objName:"Ops.Extension.Deprecated.PointsCircle"};Ops.Gl.Textures.CopyTexture=function(){CABLES.Op.apply(this,arguments);const e=this;const k=e.attachments={copytexture_frag:"UNI float a;\nUNI sampler2D tex;\n\n#ifdef TEX_MASK\nUNI sampler2D texMask;\n#endif\n\nIN vec2 texCoord;\n\nvoid main()\n{\n    vec4 col=texture(tex,texCoord);\n\n    #ifdef TEX_MASK\n        col.a=texture(texMask,texCoord).r;\n    #endif\n\n\n    #ifdef GREY_R\n        col.rgb=vec3(col.r);\n    #endif\n\n    #ifdef GREY_G\n        col.rgb=vec3(col.g);\n    #endif\n\n    #ifdef GREY_B\n        col.rgb=vec3(col.b);\n    #endif\n\n    #ifdef GREY_A\n        col.rgb=vec3(col.a);\n    #endif\n\n    #ifdef GREY_LUMI\n        col.rgb=vec3( dot(vec3(0.2126,0.7152,0.0722), col.rgb) );\n    #endif\n\n\n    #ifdef INVERT_A\n        col.a=1.0-col.a;\n    #endif\n\n    #ifdef INVERT_R\n        col.r=1.0-col.r;\n    #endif\n\n    #ifdef INVERT_G\n        col.g=1.0-col.g;\n    #endif\n\n    #ifdef INVERT_B\n        col.b=1.0-col.b;\n    #endif\n\n    #ifdef ALPHA_1\n        col.a=1.0;\n    #endif\n\n\n\n\n    outColor= col;\n}"};const t=e.inTriggerButton("render"),n=e.inTexture("Texture"),i=e.inTexture("Alpha Mask"),r=e.inValueBool("use original size",true),s=e.inValueInt("width",640),a=e.inValueInt("height",360),o=e.inSwitch("filter",["nearest","linear","mipmap"],"linear"),l=e.inValueSelect("wrap",["clamp to edge","repeat","mirrored repeat"],"clamp to edge"),h=e.inValueBool("HDR"),u=e.inSwitch("Alpha Mask Source",["A","1"],"A"),f=e.inSwitch("Convert Greyscale",["Off","R","G","B","A","Luminance"],"Off"),c=e.inBool("Invert R",false),d=e.inBool("Invert G",false),m=e.inBool("Invert B",false),M=e.inBool("Invert A",false),g=e.outTrigger("trigger"),p=e.outTexture("texture_out",null),P=e.outNumber("Aspect Ratio");u.setUiAttribs({hidePort:true});f.setUiAttribs({hidePort:true});c.setUiAttribs({hidePort:true});d.setUiAttribs({hidePort:true});m.setUiAttribs({hidePort:true});let F=null;const A=e.patch.cgl;let C=null;let _=null;let E=null;let v=true;let b=2,B=2;const D=[0,0,0,0];let y=true;e.setPortGroup("Size",[r,s,a]);const x=new CGL.Shader(A,"copytexture",this);x.setSource(x.getDefaultVertexShader(),k.copytexture_frag);const U=new CGL.Uniform(x,"t","tex",0);let V=new CGL.Uniform(x,"t","texMask",1);let S=CGL.Texture.FILTER_LINEAR;let T=CGL.Texture.WRAP_CLAMP_TO_EDGE;u.onChange=f.onChange=c.onChange=d.onChange=m.onChange=l.onChange=o.onChange=h.onChange=i.onChange=I;t.onLinkChanged=n.onLinkChanged=n.onChange=()=>{I()};t.onTriggered=R;L();function O(){if(_)_.delete();if(E){E.delete();E=null}_=new CGL.TextureEffect(A,{isFloatingPointTexture:h.get(),clear:false});if(!E||E.width!=Math.floor(s.get())||E.height!=Math.floor(a.get())||E.wrap!=T||E.isFloatingPoint()!=h.get()){if(E)E.delete();E=new CGL.Texture(A,{name:"copytexture_"+e.id,isFloatingPointTexture:h.get(),filter:S,wrap:T,width:Math.floor(s.get()),height:Math.floor(a.get())})}_.setSourceTexture(E);p.set(null);y=false}function I(){G();if(t.links.length===0){y=true;e.patch.cgl.off(F);F=e.patch.cgl.on("beginFrame",()=>{e.patch.cgl.off(F);if(v)w();if(!_)e.log("has no effect");if(!n.get())e.log("has no intexture");R()})}}function w(){if(!n.get()||n.get()==CGL.Texture.getEmptyTexture(A))return;if(!_)O();if(r.get()){b=n.get().width;B=n.get().height}else{b=Math.floor(s.get());B=Math.floor(a.get())}if((b!=E.width||B!=E.height)&&(b!==0&&B!==0)){a.set(B);s.set(b);E.filter=S;E.setSize(b,B);P.set(b/B);_.setSourceTexture(E)}if(p.get()&&S!=CGL.Texture.FILTER_NEAREST){if(!p.get().isPowerOfTwo())e.setUiError("hintnpot","texture dimensions not power of two! - texture filtering when scaling will not work on ios devices.",0);else e.setUiError("hintnpot",null,0)}else e.setUiError("hintnpot",null,0);v=false}function L(){s.setUiAttribs({greyout:r.get()});a.setUiAttribs({greyout:r.get()})}function N(){v=true;I()}r.onChange=function(){L();if(r.get()){s.onChange=null;a.onChange=null}else{s.onChange=N;a.onChange=N}w()};function R(){if(!n.get()||n.get()==CGL.Texture.getEmptyTexture(A))p.set(CGL.Texture.getEmptyTexture(A));if(!n.get()||n.get()==CGL.Texture.getEmptyTexture(A)){C=null;g.trigger();return}else if(!_||y||C!=n.get()){O()}const e=A.getViewPort();D[0]=e[0];D[1]=e[1];D[2]=e[2];D[3]=e[3];w();C=n.get();const t=A.currentTextureEffect;A.currentTextureEffect=_;_.setSourceTexture(E);_.startEffect();A.pushShader(x);A.currentTextureEffect.bind();A.setTexture(0,n.get().tex);if(i.get())A.setTexture(1,i.get().tex);A.pushBlend(false);A.currentTextureEffect.finish();A.popShader();A.popBlend();p.set(_.getCurrentSourceTexture());_.endEffect();A.setViewPort(D[0],D[1],D[2],D[3]);A.currentTextureEffect=t;A.setTexture(0,CGL.Texture.getEmptyTexture(A).tex);g.trigger()}function G(){x.toggleDefine("TEX_MASK",i.get());x.toggleDefine("GREY_R",f.get()==="R");x.toggleDefine("GREY_G",f.get()==="G");x.toggleDefine("GREY_B",f.get()==="B");x.toggleDefine("GREY_A",f.get()==="A");x.toggleDefine("GREY_LUMI",f.get()==="Luminance");x.toggleDefine("ALPHA_1",u.get()==="1");x.toggleDefine("ALPHA_A",u.get()==="A");x.toggleDefine("INVERT_R",c.get());x.toggleDefine("INVERT_G",d.get());x.toggleDefine("INVERT_B",m.get());x.toggleDefine("INVERT_A",M.get());if(l.get()=="repeat")T=CGL.Texture.WRAP_REPEAT;else if(l.get()=="mirrored repeat")T=CGL.Texture.WRAP_MIRRORED_REPEAT;else if(l.get()=="clamp to edge")T=CGL.Texture.WRAP_CLAMP_TO_EDGE;if(o.get()=="nearest")S=CGL.Texture.FILTER_NEAREST;else if(o.get()=="linear")S=CGL.Texture.FILTER_LINEAR;else if(o.get()=="mipmap")S=CGL.Texture.FILTER_MIPMAP;if(x.needsRecompile()){y=true}if(E&&(E.width!=Math.floor(s.get())||E.height!=Math.floor(a.get())||E.wrap!=T||E.isFloatingPoint()!=h.get())){y=true}}};Ops.Gl.Textures.CopyTexture.prototype=new CABLES.Op;CABLES.OPS["18a6d1f4-a7f8-4a3e-ab1d-0c2d2efe3861"]={f:Ops.Gl.Textures.CopyTexture,objName:"Ops.Gl.Textures.CopyTexture"};Ops.Array.WeaveArrays=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};let a=e.inArray("Array 1");let o=e.inArray("Array 2");let l=e.inValue("Chunk Size",1);let h=e.outArray("Combined Array");a.onChange=n;o.onChange=n;l.onChange=n;function n(){let n=[];let i=a.get();let r=o.get();let s=l.get();if(s<1){s=1}if(i&&!r){n=i.slice(0)}if(!i&&r){n=r.slice(0)}else if(i&&r){for(let t=0;t<Math.max(i.length,r.length);t+=s){for(let e=0;e<s&&e+t<i.length;e++){n.push(i[t+e])}for(let e=0;e<s&&e+t<r.length;e++){n.push(r[t+e])}}}h.set(null);h.set(n)}};Ops.Array.WeaveArrays.prototype=new CABLES.Op;CABLES.OPS["ad6d77b7-d81d-4115-a2f2-5160adaaef3a"]={f:Ops.Array.WeaveArrays,objName:"Ops.Array.WeaveArrays"};Ops.Extension.Deprecated.Array3FlipAxis=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const r=e.inArray("Points",3),s=e.inSwitch("Axis 1",["X","Y","Z"],"X"),a=e.inSwitch("Axis 2",["X","Y","Z"],"Y"),o=e.inSwitch("Axis 3",["X","Y","Z"],"Z"),l=e.inBool("Flip Order X",false),h=e.inBool("Flip Order Y",false),u=e.inBool("Flip Order Z",false),f=e.outArray("Result");const c=[];r.onChange=l.onChange=h.onChange=u.onChange=s.onChange=a.onChange=o.onChange=()=>{const t=r.get();if(!t||t.length==0){f.set(null);return}c.length=t.length;let n=t.length;if(s.get()=="X")for(let e=0;e<n;e+=3)c[e+0]=t[e+0];if(s.get()=="Y")for(let e=0;e<n;e+=3)c[e+0]=t[e+1];if(s.get()=="Z")for(let e=0;e<n;e+=3)c[e+0]=t[e+2];if(a.get()=="X")for(let e=0;e<n;e+=3)c[e+1]=t[e+0];if(a.get()=="Y")for(let e=0;e<n;e+=3)c[e+1]=t[e+1];if(a.get()=="Z")for(let e=0;e<n;e+=3)c[e+1]=t[e+2];if(o.get()=="X")for(let e=0;e<n;e+=3)c[e+2]=t[e+0];if(o.get()=="Y")for(let e=0;e<n;e+=3)c[e+2]=t[e+1];if(o.get()=="Z")for(let e=0;e<n;e+=3)c[e+2]=t[e+2];const e=n;if(l.get())for(let e=0;e<n/2;e+=3){const i=c[e+0];c[e+0]=c[n-e];c[n-e]=i}if(h.get())for(let e=0;e<n/2;e+=3){const i=c[e+1];c[e+1]=c[n-e+1];c[n-e+1]=i}if(u.get())for(let e=0;e<n/2;e+=3){const i=c[e+2];c[e+2]=c[n-e+2];c[n-e+2]=i}f.set(null);f.set(c)}};Ops.Extension.Deprecated.Array3FlipAxis.prototype=new CABLES.Op;CABLES.OPS["1a9a0178-5906-423b-b8f3-0532499ba169"]={f:Ops.Extension.Deprecated.Array3FlipAxis,objName:"Ops.Extension.Deprecated.Array3FlipAxis"};Ops.Gl.Matrix.Transform=function(){CABLES.Op.apply(this,arguments);const n=this;const e=n.attachments={};const t=n.inTrigger("render"),i=n.inValue("posX",0),r=n.inValue("posY",0),s=n.inValue("posZ",0),a=n.inValue("scale",1),o=n.inValue("rotX",0),l=n.inValue("rotY",0),h=n.inValue("rotZ",0),u=n.outTrigger("trigger");n.setPortGroup("Rotation",[o,l,h]);n.setPortGroup("Position",[i,r,s]);n.setPortGroup("Scale",[a]);n.setUiAxisPorts(i,r,s);n.toWorkPortsNeedToBeLinked(t,u);const f=vec3.create();const c=vec3.create();const d=mat4.create();mat4.identity(d);let m=false,g=false,p=true,F=true,A=true;o.onChange=l.onChange=h.onChange=B;i.onChange=r.onChange=s.onChange=v;a.onChange=b;t.onTriggered=function(){let e=false;if(p){_();e=true}if(F){E();e=true}if(A)e=true;if(e)C();const t=n.patch.cg||n.patch.cgl;t.pushModelMatrix();mat4.multiply(t.mMatrix,t.mMatrix,d);u.trigger();t.popModelMatrix();if(CABLES.UI){if(!i.isLinked()&&!r.isLinked()&&!s.isLinked()){gui.setTransform(n.id,i.get(),r.get(),s.get());if(n.isCurrentUiOp())gui.setTransformGizmo({posX:i,posY:r,posZ:s})}}};function C(){mat4.identity(d);if(g)mat4.translate(d,d,f);if(o.get()!==0)mat4.rotateX(d,d,o.get()*CGL.DEG2RAD);if(l.get()!==0)mat4.rotateY(d,d,l.get()*CGL.DEG2RAD);if(h.get()!==0)mat4.rotateZ(d,d,h.get()*CGL.DEG2RAD);if(m)mat4.scale(d,d,c);A=false}function _(){g=false;if(i.get()!==0||r.get()!==0||s.get()!==0)g=true;vec3.set(f,i.get(),r.get(),s.get());p=false}function E(){m=true;vec3.set(c,a.get(),a.get(),a.get());F=false}function v(){p=true}function b(){F=true}function B(){A=true}C()};Ops.Gl.Matrix.Transform.prototype=new CABLES.Op;CABLES.OPS["650baeb1-db2d-4781-9af6-ab4e9d4277be"]={f:Ops.Gl.Matrix.Transform,objName:"Ops.Gl.Matrix.Transform"};Ops.Gl.ImageCompose.Color_v2=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={color_frag:"IN vec2 texCoord;\nUNI sampler2D tex;\nUNI float r;\nUNI float g;\nUNI float b;\nUNI float a;\nUNI float amount;\n\n#ifdef MASK\n    UNI sampler2D mask;\n#endif\n\n{{CGL.BLENDMODES3}}\n\nvoid main()\n{\n    vec4 col=vec4(r,g,b,a);\n    vec4 base=texture(tex,texCoord);\n\n    float am=amount;\n    #ifdef MASK\n        float msk=texture(mask,texCoord).r;\n        #ifdef INVERTMASK\n            msk=1.0-msk;\n        #endif\n        am*=1.0-msk;\n    #endif\n\n    outColor=cgl_blendPixel(base,col,am);\n}\n"};const n=e.inTrigger("render"),i=CGL.TextureEffect.AddBlendSelect(e),r=e.inValueSlider("Amount",1),s=CGL.TextureEffect.AddBlendAlphaMask(e),a=e.inTexture("Mask"),o=e.inValueBool("Mask Invert"),l=e.inValueSlider("r",Math.random()),h=e.inValueSlider("g",Math.random()),u=e.inValueSlider("b",Math.random()),f=e.inValueSlider("A",1),c=e.outTrigger("trigger");l.setUiAttribs({colorPick:true});e.setPortGroup("Color",[l,h,u]);const d=0;const m=e.patch.cgl;const g=new CGL.Shader(m,"textureeffect color");const p=t.color_frag||"";g.setSource(g.getDefaultVertexShader(),p);CGL.TextureEffect.setupBlending(e,g,i,r,s);const F=new CGL.Uniform(g,"t","tex",d),A=new CGL.Uniform(g,"t","mask",1),C=new CGL.Uniform(g,"f","r",l),_=new CGL.Uniform(g,"f","g",h),E=new CGL.Uniform(g,"f","b",u),v=new CGL.Uniform(g,"f","a",f),b=new CGL.Uniform(g,"f","amount",r);a.onChange=function(){if(a.isLinked())g.define("MASK");else g.removeDefine("MASK")};o.onChange=function(){if(o.get())g.define("INVERTMASK");else g.removeDefine("INVERTMASK")};n.onTriggered=function(){if(!CGL.TextureEffect.checkOpInEffect(e,3))return;m.pushShader(g);m.currentTextureEffect.bind();m.setTexture(d,m.currentTextureEffect.getCurrentSourceTexture().tex);if(a.get())m.setTexture(1,a.get().tex);m.currentTextureEffect.finish();m.popShader();c.trigger()}};Ops.Gl.ImageCompose.Color_v2.prototype=new CABLES.Op;CABLES.OPS["6dada2b7-da7c-47ee-87a9-a12e87055208"]={f:Ops.Gl.ImageCompose.Color_v2,objName:"Ops.Gl.ImageCompose.Color_v2"};Ops.Gl.ImageCompose.Hue=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={hue_frag:"UNI float hue;\n\n#ifdef HAS_TEXTURES\n  IN vec2 texCoord;\n  UNI sampler2D tex;\n#endif\n\n#ifdef TEX_MASK\n    UNI sampler2D texMask;\n#endif\n#ifdef TEX_OFFSET\n    UNI sampler2D texOffset;\n#endif\n\nvec3 rgb2hsv(vec3 c)\n{\n    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n    vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n\n    float d = q.x - min(q.w, q.y);\n    float e = 1.0e-10;\n    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n}\n\nvec3 hsv2rgb(vec3 c)\n{\n    vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n    vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n}\n\nvoid main()\n{\n   vec4 col=vec4(1.0,0.0,0.0,1.0);\n    #ifdef HAS_TEXTURES\n        col=texture(tex,texCoord);\n        float h=hue;\n\n        #ifdef TEX_OFFSET\n            h += texture(texOffset,texCoord).r;\n        #endif\n\n\n        vec3 hsv = rgb2hsv(col.rgb);\n        hsv.x=hsv.x+h;\n\n        #ifndef TEX_MASK\n            col.rgb = hsv2rgb(hsv);\n        #endif\n\n        #ifdef TEX_MASK\n            col.rgb = mix(col.rgb,hsv2rgb(hsv),texture(texMask,texCoord).r);\n        #endif\n\n   #endif\n   outColor= col;\n}"};const n=e.inTrigger("render"),i=e.inValueSlider("hue",1),r=e.inTexture("Mask"),s=e.inTexture("Offset"),a=e.outTrigger("trigger");const o=e.patch.cgl;const l=new CGL.Shader(o,e.name,e);l.setSource(l.getDefaultVertexShader(),t.hue_frag);const h=new CGL.Uniform(l,"t","tex",0);const u=new CGL.Uniform(l,"t","texMask",1);const f=new CGL.Uniform(l,"t","texOffset",2);const c=new CGL.Uniform(l,"f","hue",1);i.onChange=function(){c.setValue(i.get())};r.onChange=s.onChange=()=>{l.toggleDefine("TEX_MASK",r.get());l.toggleDefine("TEX_OFFSET",s.get())};n.onTriggered=function(){if(!CGL.TextureEffect.checkOpInEffect(e))return;o.pushShader(l);o.currentTextureEffect.bind();o.setTexture(0,o.currentTextureEffect.getCurrentSourceTexture().tex);if(r.get())o.setTexture(1,r.get().tex);if(s.get())o.setTexture(2,s.get().tex);o.currentTextureEffect.finish();o.popShader();a.trigger()}};Ops.Gl.ImageCompose.Hue.prototype=new CABLES.Op;CABLES.OPS["94ef0da0-c920-415c-81b0-fecbd437991d"]={f:Ops.Gl.ImageCompose.Hue,objName:"Ops.Gl.ImageCompose.Hue"};Ops.Color.ColorPalettes=function(){CABLES.Op.apply(this,arguments);const t=this;const e=t.attachments={};const n=t.inValueInt("Index",0);const i=t.outTexture("Texture");const s=t.inValueBool("Smooth");const a=t.outArray("Color Array");let o=document.createElement("canvas");o.id="canvas_"+CABLES.generateUUID();o.width=5;o.height=8;o.style.display="none";let r=document.getElementsByTagName("body")[0];r.appendChild(o);let l=o.getContext("2d");n.onChange=s.onChange=g;let h=[];h.length=5*3;let u=null;g();function f(e){return parseInt(m(e).substring(0,2),16)}function c(e){return parseInt(m(e).substring(2,4),16)}function d(e){return parseInt(m(e).substring(4,6),16)}function m(e=""){return e.charAt(0)=="#"?e.substring(1,7):e}function g(){t.patch.cgl.addNextFrameOnceCallback(p)}function p(){let r=Math.round(n.get())*5;if(r>=F.length-5)r=0;if(r<0)r=0;if(r!=r)r=0;for(let i=0;i<5;i++){let e=f(F[r+i]);let t=c(F[r+i]);let n=d(F[r+i]);h[i*3+0]=e/255;h[i*3+1]=t/255;h[i*3+2]=n/255;l.fillStyle="rgb("+e+","+t+","+n+")";l.fillRect(o.width/5*i,0,o.width/5,o.height)}let e=CGL.Texture.FILTER_NEAREST;if(s.get())e=CGL.Texture.FILTER_LINEAR;if(u==e&&i.get())i.get().initTexture(o,e);else i.set(new CGL.Texture.createFromImage(t.patch.cgl,o,{filter:e}));a.set(null);a.set(h);i.get().unpackAlpha=false;u=e}t.onDelete=function(){o.remove()};const F=["#E6E2AF","#A7A37E","#EFECCA","#046380","002F2F","#468966","#FFF0A5","#FFB03B","#B64926","8E2800","#FCFFF5","#D1DBBD","#91AA9D","#3E606F","193441","#FF6138","#FFFF9D","#BEEB9F","#79BD8F","00A388","#105B63","#FFFAD5","#FFD34E","#DB9E36","BD4932","#225378","#1695A3","#ACF0F2","#F3FFE2","EB7F00","#2C3E50","#E74C3C","#ECF0F1","#3498DB","2980B9","#000000","#263248","#7E8AA2","#FFFFFF","FF9800","#004358","#1F8A70","#BEDB39","#FFE11A","FD7400","#DC3522","#D9CB9E","#374140","#2A2C2B","1E1E20","#7D8A2E","#C9D787","#FFFFFF","#FFC0A9","FF8598","#B9121B","#4C1B1B","#F6E497","#FCFAE1","BD8D46","#2E0927","#D90000","#FF2D00","#FF8C00","04756F","#595241","#B8AE9C","#FFFFFF","#ACCFCC","8A0917","#10222B","#95AB63","#BDD684","#E2F0D6","F6FFE0","#F6F792","#333745","#77C4D3","#DAEDE2","EA2E49","#703030","#2F343B","#7E827A","#E3CDA4","C77966","#2F2933","#01A2A6","#29D9C2","#BDF271","FFFFA6","#D8CAA8","#5C832F","#284907","#382513","363942","#FFF8E3","#CCCC9F","#33332D","#9FB4CC","DB4105","#85DB18","#CDE855","#F5F6D4","#A7C520","493F0B","#04BFBF","#CAFCD8","#F7E967","#A9CF54","588F27","#292929","#5B7876","#8F9E8B","#F2E6B6","412A22","#332532","#644D52","#F77A52","#FF974F","A49A87","#405952","#9C9B7A","#FFD393","#FF974F","F54F29","#2B3A42","#3F5765","#BDD4DE","#EFEFEF","FF530D","#962D3E","#343642","#979C9C","#F2EBC7","348899","#96CA2D","#B5E655","#EDF7F2","#4BB5C1","7FC6BC","#1C1D21","#31353D","#445878","#92CDCF","EEEFF7","#3E454C","#2185C5","#7ECEFD","#FFF6E5","FF7F66","#00585F","#009393","#FFFCC4","#F0EDBB","FF3800","#B4AF91","#787746","#40411E","#32331D","C03000","#63A69F","#F2E1AC","#F2836B","#F2594B","CD2C24","#88A825","#35203B","#911146","#CF4A30","ED8C2B","#F2385A","#F5A503","#E9F1DF","#4AD9D9","36B1BF","#CFC291","#FFF6C5","#A1E8D9","#FF712C","695D46","#FF5335","#B39C85","#306E73","#3B424D","1D181F","#000000","#333333","#FF358B","#01B0F0","AEEE00","#E8E595","#D0A825","#40627C","#26393D","FFFAE4","#E7E8D1","#D3CEAA","#FBF7E4","#424242","8E001C","#354242","#ACEBAE","#FFFF9D","#C9DE55","7D9100","#2F2933","#01A2A6","#29D9C2","#BDF271","FFFFA6","#DDDCC5","#958976","#611427","#1D2326","6A6A61","#6C6E58","#3E423A","#417378","#A4CFBE","F4F7D9","#E1E6FA","#C4D7ED","#ABC8E2","#375D81","183152","#6B0C22","#D9042B","#F4CB89","#588C8C","011C26","#304269","#91BED4","#D9E8F5","#FFFFFF","F26101","#96CEB4","#FFEEAD","#FF6F69","#FFCC5C","AAD8B0","#B0CC99","#677E52","#B7CA79","#F6E8B1","89725B","#334D5C","#45B29D","#EFC94C","#E27A3F","DF5A49","#16193B","#35478C","#4E7AC7","#7FB2F0","ADD5F7","#00261C","#044D29","#168039","#45BF55","96ED89","#36362C","#5D917D","#A8AD80","#E6D4A7","825534","#F9E4AD","#E6B098","#CC4452","#723147","31152B","#2C3E50","#FC4349","#D7DADB","#6DBCDB","FFFFFF","#002635","#013440","#AB1A25","#D97925","EFE7BE","#FF8000","#FFD933","#CCCC52","#8FB359","192B33","#272F32","#9DBDC6","#FFFFFF","#FF3D2E","DAEAEF","#B8ECD7","#083643","#B1E001","#CEF09D","476C5E","#002F32","#42826C","#A5C77F","#FFC861","C84663","#5C4B51","#8CBEB2","#F2EBBF","#F3B562","F06060","#5A1F00","#D1570D","#FDE792","#477725","A9CC66","#5E0042","#2C2233","#005869","#00856A","8DB500","#52656B","#FF3B77","#CDFF00","#FFFFFF","B8B89F","#801637","#047878","#FFB733","#F57336","C22121","#730046","#BFBB11","#FFC200","#E88801","C93C00","#24221F","#363F45","#4B5F6D","#5E7C88","FEB41C","#E64661","#FFA644","#998A2F","#2C594F","002D40","#C24704","#D9CC3C","#FFEB79","#A0E0A9","00ADA7","#484A47","#C1CE96","#ECEBF0","#687D77","353129","#588C7E","#F2E394","#F2AE72","#D96459","8C4646","#BAB293","#A39770","#EFE4BD","#A32500","2B2922","#6A7059","#FDEEA7","#9BCC93","#1A9481","003D5C","#174C4F","#207178","#FF9666","#FFE184","F5E9BE","#D5FBFF","#9FBCBF","#647678","#2F3738","59D8E6","#DB5800","#FF9000","#F0C600","#8EA106","59631E","#450003","#5C0002","#94090D","#D40D12","FF1D23","#211426","#413659","#656F8C","#9BBFAB","F2EFDF","#EA6045","#F8CA4D","#F5E5C0","#3F5666","2F3440","#F2F2F2","#C6E070","#91C46C","#287D7D","1C344D","#334D5C","#45B29D","#EFC94C","#E27A3F","DF5A49","#705B35","#C7B07B","#E8D9AC","#FFF6D9","570026","#F7F2B2","#ADCF4F","#84815B","#4A1A2C","8E3557","#1A1F2B","#30395C","#4A6491","#85A5CC","D0E4F2","#25064D","#36175E","#553285","#7B52AB","9768D1","#004056","#2C858D","#74CEB7","#C9FFD5","FFFFCB","#CFCA4C","#FCF5BF","#9FE5C2","#5EB299","745A33","#776045","#A8C545","#DFD3B6","#FFFFFF","0092B2","#CC3910","#F1F2C0","#CCC59E","#8FA68E","332F29","#FF6600","#C13B00","#5E6D70","#424E4F","1B1D1E","#690011","#BF0426","#CC2738","#F2D99C","E5B96F","#1B1D26","#425955","#778C7A","#F1F2D8","BFBD9F","#F6B1C3","#F0788C","#DE264C","#BC0D35","A20D1E","#597533","#332F28","#61B594","#E6DEA5","C44E18","#3FB8AF","#7FC7AF","#DAD8A7","#FF9E9D","FF3D7F","#0F2D40","#194759","#296B73","#3E8C84","D8F2F0","#42282F","#74A588","#D6CCAD","#DC9C76","D6655A","#002A4A","#17607D","#FFF1CE","#FF9311","D64700","#003056","#04518C","#00A1D9","#47D9BF","F2D03B","#13140F","#D4FF00","#E4FFE6","#68776C","00D6DD","#FCFAD0","#A1A194","#5B605F","#464646","A90641","#289976","#67CC8E","#B1FF91","#FFE877","FF5600","#302B1D","#3F522B","#737D26","#A99E46","D9CB84","#56626B","#6C9380","#C0CA55","#F07C6C","AD5472","#32450C","#717400","#DC8505","#EC5519","BE2805","#C7B773","#E3DB9A","#F5FCD0","#B1C2B3","778691","#E83A25","#FFE9A3","#98CC96","#004563","191B28","#3399CC","#67B8DE","#91C9E8","#B4DCED","E8F8FF","#1A212C","#1D7872","#71B095","#DEDBA7","D13F32","#7D2A35","#CC9258","#917A56","#B4BA6C","FEFFC2","#E7E9D1","#D3D4AA","#FCFAE6","#444444","901808","#FFFFFF","#AEAEAE","#E64C66","#2D3E50","1BBC9B","#E0FFB3","#61C791","#31797D","#2A2F36","F23C55","#EB5937","#1C1919","#403D3C","#456F74","D3CBBD","#E6DD00","#8CB302","#008C74","#004C66","332B40","#14A697","#F2C12E","#F29D35","#F27649","F25252","#261822","#40152A","#731630","#CC1E2C","FF5434","#261F27","#FEE169","#CDD452","#F9722E","C9313D","#5C4B51","#8CBEB2","#F2EBBF","#F3B562","F06060","#2F3837","#C5C7B6","#FFF8D3","#4C493E","222028","#E3CBAC","#9C9985","#C46D3B","#788880","324654","#3F0B1B","#7A1631","#CF423C","#FC7D49","FFD462","#14212B","#293845","#4F6373","#8F8164","D9D7AC","#98A89E","#BAC0AC","#FAFAC6","#FF4411","D40015","#FEFFFF","#3C3F36","#9FB03E","#EBE9DC","72918B","#CC6B32","#FFAB48","#FFE7AD","#A7C9AE","888A63","#262526","#404040","#8C8979","#F2F2F2","F60A20","#00305A","#004B8D","#0074D9","#4192D9","7ABAF2","#0C273D","#54D0ED","#FFFEF1","#70B85D","2C5E2E","#4C1B33","#EFE672","#98A942","#2D6960","141D14","#2F3540","#666A73","#F2EDE4","#D9D1C7","8C8681","#0D1F30","#3B6670","#8BADA3","#F0E3C0","DB6C0F","#FFBC67","#DA727E","#AC6C82","#685C79","455C7B","#092140","#024959","#F2C777","#F24738","BF2A2A","#133463","#365FB7","#799AE0","#F4EFDC","BA9B65","#C4D4CB","#55665E","#30282A","#542733","E84167","#CDDEC6","#4DAAAB","#1E4F6A","#2A423C","93A189","#EF5411","#FA5B0F","#FF6517","#FF6D1F","FF822E","#41434A","#6E9489","#DEDCC3","#F2F1E9","877963","#292929","#2BBFBD","#F2B33D","#F29B30","F22E2E","#F2385A","#F5A503","#E9F1DF","#56D9CD","3AA1BF","#D5F8B4","#A6E3A8","#8A9A85","#7E566B","422335","#3CBAC8","#93EDD4","#F3F5C4","#F9CB8F","F19181","#979926","#38CCB5","#EEFF8E","#FFD767","CC2A09","#404040","#024959","#037E8C","#F2EFDC","F24C27","#94B34D","#D3FF82","#363D52","#121D2B","111B1C","#282E33","#25373A","#164852","#495E67","FF3838","#313732","#8AA8B0","#DEDEDE","#FFFFFF","F26101","#FFFFFF","#E5E1D1","#52616D","#2C343B","C44741","#FFF6B8","#ABCCA7","#403529","#7A5E2F","A68236","#4F1025","#C5003E","#D9FF5B","#78AA00","15362D","#49404F","#596166","#D1FFCD","#A9BD8B","948A54","#FF2151","#FF7729","#FFAD29","#FFEBCA","1AB58A","#73603D","#BF8A49","#F2CA80","#5E5A59","0D0D0D","#3D4C53","#70B7BA","#F1433F","#E7E1D4","FFFFFF","#006D8D","#008A6E","#549E39","#8AB833","C0CF3A","#BDDFB3","#2BAA9C","#2F2E2E","#0F2625","465F3F","#F2F2F2","#BF0404","#8C0303","#590202","400101","#76A19A","#272123","#A68D60","#B0C5BB","D9593D","#0E3D59","#88A61B","#F29F05","#F25C05","D92525","#C1E1ED","#76C7C6","#273D3B","#131A19","E35C14","#2D112C","#530031","#820233","#CA293E","EF4339","#AF7575","#EFD8A1","#BCD693","#AFD7DB","3D9CA8","#D74B4B","#DCDDD8","#475F77","#354B5E","FFFFFF","#FFF6C9","#C8E8C7","#A4DEAB","#85CC9F","499E8D","#229396","#8BA88F","#C7C5A7","#F0DFD0","F23C3C","#57385C","#A75265","#EC7263","#FEBE7E","FFEDBC","#96526B","#D17869","#EBAD60","#F5CF66","8BAB8D","#0D1C33","#17373C","#2B6832","#4F9300","A1D700","#1B2B32","#37646F","#A3ABAF","#E1E7E8","B22E2F","#C5D9B2","#53A194","#572C2C","#3D2324","695A3B","#425957","#81AC8B","#F2E5A2","#F89883","D96666","#002E40","#2A5769","#FFFFFF","#FABD4A","FA9600","#FFFEFC","#E2E3DF","#515B5E","#2E3233","CAF200","#FFF0A3","#B8CC6E","#4B6000","#E4F8FF","004460","#3B596A","#427676","#3F9A82","#A1CD73","ECDB60","#F2E6CE","#8AB39F","#606362","#593325","1D1D1F","#212B40","#C2E078","#FFFFFF","#BADCDD","547B97","#0B3C4D","#0E5066","#136480","#127899","1A8BB3","#222130","#464D57","#D4E8D3","#FFFCFB","ED8917","#B33600","#FF8A00","#FFC887","#CC5400","B31E00","#012530","#28544B","#ACBD86","#FFD6A0","FF302C","#2E95A3","#50B8B4","#C6FFFA","#E2FFA8","D6E055","#112F41","#068587","#4FB99F","#F2B134","ED553B","#202B30","#4E7178","#4FA9B8","#74C0CF","F1F7E2","#302B2F","#696153","#FFA600","#9BB58F","FFD596","#458C6B","#F2D8A7","#D9A86C","#D94436","A62424","#22475E","#75B08A","#F0E797","#FF9D84","FF5460","#FFAA5C","#DA727E","#AC6C82","#685C79","455C7B","#686E75","#9BAAC1","#82787B","#E4F1DB","AAC19B","#F0C755","#E2AD3B","#BF5C00","#901811","5C110F","#FFFBDC","#BFBCA5","#7F7D6E","#3F3E37","E5E2C6","#BEBEBE","#F1E4D8","#594735","#94C7BA","D8F1E4","#1B1E26","#F2EFBD","#B6D051","#70A99A","2F6D7A","#F7E4A2","#A7BD5B","#DC574E","#8DC7B8","ED9355","#70E8CB","#FFE9C7","#FF5B5B","#545454","2D2D2F","#17111A","#321433","#660C47","#B33467","CCBB51","#2B2E2E","#595855","#A2ABA5","#CAE6E8","313F54","#023B47","#295E52","#F2E085","#FCAB55","EE7F38","#302C29","#D1D1BC","#A7C4BB","#6C8C84","466964","#212629","#067778","#49B8A8","#85EDB6","D9E5CD","#334D5C","#45B29D","#EFC94C","#E27A3F","DF4949","#2C3E50","#FC4349","#6DBCDB","#D7DADB","FFFFFF","#35262D","#FFFBFF","#E8ECED","#A4B7BB","76A0B0","#61E8D2","#FCEEB9","#302F25","#704623","BBE687","#E1E6B9","#C4D7A4","#ABC8A4","#375D3B","183128","#C98B2F","#803C27","#C56520","#E1B41B","807916","#A3D9B0","#93BF9E","#F2F0D5","#8C8474","40362E","#524656","#CF4747","#EA7A58","#E4DCCB","A6C4BC","#5C2849","#A73E5C","#EC4863","#FFDA66","1FCECB","#0EEAFF","#15A9FA","#1B76FF","#1C3FFD","2C1DFF","#010000","#393845","#9B96A3","#5C0009","940315","#468071","#FFE87A","#FFCA53","#FF893B","E62738","#404040","#024959","#037E8C","#F2EFDC","F24C27","#FF765E","#C2AE8B","#FCCF65","#FFE5C6","B7BDC4","#003647","#00717D","#F2D8A7","#A4A66A","515932","#FAFAC0","#C4BE90","#8C644C","#594D37","293033","#2B3A42","#3F5765","#BDD4DE","#EFEFEF","E74C3C","#3B3B3B","#A8877E","#FFA49D","#FF7474","FF476C","#0A3A4A","#196674","#33A6B2","#9AC836","D0E64B","#FFA340","#38001C","#571133","#017A74","00C2BA","#DCEBDD","#A0D5D6","#789AA1","#304345","AD9A27","#588C7E","#F2E394","#F2AE72","#D96459","8C4646","#F0E6B1","#B5D6AA","#99A37A","#70584B","3D3536","#2F400D","#8CBF26","#A8CA65","#E8E5B0","419184","#010712","#13171F","#1C1F26","#24262D","961227","#403F33","#6E755F","#AFC2AA","#FFDEA1","E64C10","#C74029","#FAE8CD","#128085","#385052","F0AD44","#CFF09E","#A8DBA8","#79BD9A","#3B8686","0B486B","#E0401C","#E6B051","#272F30","#F7EDB7","9E2B20","#FFE2C5","#FFEEDD","#FFDDAA","#FFC484","FFDD99","#FFFFE4","#F2E5BD","#B9BF8E","#A69F7C","8C6865","#5C8A2D","#AFD687","#FFFFFF","#00C3A9","008798","#4F3130","#FF1F3D","#5BE3E3","#FDFFF1","8B9698","#D23600","#D95100","#DE6D00","#EE8900","FCA600","#FFFFFA","#A1A194","#5B605F","#464646","FF6600","#F34A53","#FAE3B4","#AAC789","#437356","1E4147","#2A7A8C","#176273","#063540","#E6D9CF","403D3A","#21455B","#567D8C","#A59E8C","#8C8372","F2F2F2","#012340","#026873","#83A603","#BBBF45","F2F0CE","#FDFF98","#A7DB9E","#211426","#6B073B","DA8C25","#002F36","#142426","#D1B748","#EDDB43","FFFD84","#420000","#600000","#790000","#931111","BF1616","#3C989E","#5DB5A4","#F4CDA5","#F57A82","ED5276","#23A38F","#B7C11E","#EFF1C2","#F0563D","2E313D","#F5ECD9","#2BACB5","#B4CCB9","#E84D5B","3B3B3B","#A5EB3C","#60C21E","#159E31","#53DB50","C5FFCB","#263138","#406155","#7C9C71","#DBC297","FF5755","#0A111F","#263248","#7E8AA2","#E3E3E3","C73226","#003B59","#00996D","#A5D900","#F2E926","FF930E","#00A19A","#04BF9D","#F2E85C","#F53D54","404040","#324152","#47535E","#796466","#C1836A","DEA677","#036F73","#84CDC2","#FEF2D8","#F18C79","EF504F","#174040","#888C65","#D9CA9C","#D98162","A65858","#56797F","#87A0A4","#FCFBDC","#F2DDB6","A6937C","#A8BAA9","#FFF5CF","#DBCDAD","#B39C7D","806854","#60655F","#AB9675","#FFE0C9","#D4CCBA","CF8442","#BDDFB3","#009D57","#2C372E","#0F2925","465F3F","#3E3947","#735360","#D68684","#F1B0B0","EBD0C4","#0A7B83","#2AA876","#FFD265","#F19C65","CE4D45","#FFFFFF","#F4921E","#858585","#C5D2DB","3E6B85","#11151E","#212426","#727564","#B9AA81","690C07","#000000","#910000","#CBB370","#FFFBF1","21786C","#F78F00","#C43911","#75003C","#37154A","0F2459","#003354","#91BED4","#D9E8F5","#FFFFFF","F26101","#3DA8A4","#7ACCBE","#FFFFF7","#FF99A1","FF5879","#64C733","#F0F0F0","#3E879E","#57524D","36302B","#343844","#2AB69D","#E65848","#FDC536","FCF2D7","#E34517","#F5FF53","#B4E85E","#00BD72","0B4239","#A84B3A","#FF9F67","#233138","#FFF7F5","4C646B","#59535E","#FAEEFF","#F1BAF3","#5D4970","372049","#FF6F22","#D9984F","#FFE8A9","#3E4237","32948A","#5D7370","#7FA6A1","#B8D9B8","#D6EDBD","FFF5BC","#FFBE00","#FFDC00","#FFD10F","#FFDE20","E8CA00","#003840","#005A5B","#007369","#008C72","02A676","#E1E6FA","#C4D7ED","#ABC8E2","#375D81","183152","#BA2F1D","#FFF8A4","#F5E67F","#264A59","1E2C30","#222526","#FFBB6E","#F28D00","#D94F00","80203B","#EBD096","#D1B882","#5D8A66","#1A6566","21445B","#F00807","#5F6273","#A4ABBF","#CCC9D1","E2E1E9","#DFE0AF","#A4BAA2","#569492","#41505E","383245","#152737","#2B4E69","#799AA5","#FFFFF0","682321","#C44C51","#FFB6B8","#FFEFB6","#A2B5BF","5F8CA3","#5ADED4","#4DAAAB","#26596A","#163342","6C98A1","#FF5B2B","#B1221C","#34393E","#8CC6D7","FFDA8C","#3D4D4D","#99992E","#E6E666","#F2FFBF","800033","#242424","#437346","#97D95C","#D9FF77","E9EB9B","#FFEBB0","#FFB05A","#F84322","#C33A1A","9F3818","#4D2B2F","#E57152","#E8DE67","#FFEFC3","C0CCAB","#A82221","#DB5E31","#EDA23E","#F2CB67","BFB840","#3B3140","#BFB8A3","#F2E0C9","#F2B9AC","D97E7E","#43464D","#9197A6","#D3DCF2","#7690CF","48577D","#EFDFBB","#9EBEA6","#335D6A","#D64F2A","7A8A7F","#000001","#313634","#C7CECF","#5C0402","941515","#334D5C","#45B29D","#EFC94C","#E27A3F","DF5A49","#F5F4E1","#D6C9B5","#B4AA97","#D44917","82877A","#19162B","#1C425C","#6ABDC4","#F0E4C5","D6C28F","#00132B","#7F9DB0","#C5E2ED","#FFFFFF","F95900","#1F3642","#6D968D","#B6CCB8","#FFE2B3","56493F","#08A689","#82BF56","#C7D93D","#E9F2A0","F2F2F2","#DE3961","#A4E670","#FFFFDC","#B3EECC","00ADA7","#849972","#D9D094","#A6A23E","#4F2F1D","8F5145","#F41C54","#FF9F00","#FBD506","#A8BF12","00AAB5","#00585F","#009393","#F5F3DC","#454445","FF5828","#FF6138","#FFFF9D","#BEEB9F","#79BD8F","00A388","#140B04","#332312","#B59D75","#E3D2B4","FFF7EA","#ED3B3B","#171F26","#77B59C","#F2E7B1","635656","#46594B","#A6977C","#D9B384","#734F30","260B01","#CCB8A3","#FF8FB1","#FFF5EA","#4E382F","B29882","#B70000","#FFFFFF","#FFCA3D","#94C4F4","0092B3","#053B44","#06736C","#A53539","#B9543C","EAD075","#E8C1B9","#FFB3AB","#FFCAB8","#E8B69C","FFCEAB","#E7F2DF","#69043B","#59023B","#231E2D","161726","#E82B1E","#E5DEAF","#A0B688","#557A66","453625","#F1E6D4","#BA3D49","#791F33","#9F9694","E3E1DC","#CED59F","#F1EDC0","#B1BEA4","#647168","282828","#2C3E50","#E74C3C","#ECF0F1","#3498DB","646464","#DE7047","#FFDE8D","#FFFFFF","#CDDE47","528540","#8EAB99","#40232B","#D95829","#D97338","DEC085","#E9662C","#EBAF3C","#00AC65","#068894","2B2B2B","#46483C","#A0AA8F","#EBE3CB","#FFFFFF","F26101","#170F0E","#290418","#505217","#FFD372","FFF1AF","#263545","#C4273C","#D7DADB","#6DBCDB","FFFFFF","#DCFAC0","#B1E1AE","#85C79C","#56AE8B","00968B","#075807","#097609","#70AF1A","#B9D40B","E5EB0B","#521000","#712800","#744E1D","#879666","F1D98C","#261F26","#3F3B40","#6C7367","#BFBF8A","F2E086","#2C3E50","#FC4349","#D7DADB","#6DBCDB","FFFFFF","#506D7D","#94CCB9","#FFECA7","#FFB170","F07D65","#3F4036","#8DA681","#F2E1C2","#BF2806","8C1D04","#990700","#CC542E","#FF964F","#FFCB7C","787730","#195073","#7F8C1F","#EE913F","#F2E5BD","9FD7C7","#1B3E59","#F2F0F0","#FFAC00","#BF0404","730202","#EA6045","#F8CA4D","#F5E5C0","#3F5666","2F3440","#F95759","#FDA099","#FFFFFF","#D9F3CB","8AC2B0","#265573","#386D73","#81A68A","#9FBF8F","D4D9B0","#E1DA36","#FFEA1B","#6FE4DA","#1DB0BC","007BBC","#013859","#185E65","#F9CC7F","#F15C25","9E1617","#36CC7C","#D6FFBE","#94D794","#228765","77A668","#94201F","#D4421F","#478A80","#D9E061","F08835","#F16233","#00B5B5","#F0F0F0","#3E4651","5C6D7E","#2E806C","#76CC99","#E0FFED","#FF5F3A","D2413C","#00393B","#00766C","#44A18E","#E5EDB6","F6695B","#734854","#F2F2E9","#D9D7C5","#A69580","736766","#03497E","#0596D5","#9DEBFC","#8D7754","FEB228","#F0E14C","#FFBB20","#FA7B12","#E85305","59CC0D","#FE4365","#FC9D9A","#F9CDAD","#C8C8A9","83AF9B","#00557C","#186D94","#3488AD","#81C1DC","BBE5F3","#DEE8D7","#918773","#420A1A","#240001","4D493A","#FFFFFF","#CAC535","#97AF25","#158471","41342C","#041F3D","#0B2E41","#165751","#448C61","9AC16D","#FA8C01","#FF6405","#577700","#082400","A0A600","#78C0F9","#FFDDCE","#FFFFFF","#FFDBE6","FE86A4","#351330","#CC2A41","#E7CAA4","#759A8A","524549","#02151A","#043A47","#087891","#C8C8C8","B31D14","#F34A53","#FAE3B4","#AAC789","#437356","1E4147","#58838C","#DAD7C7","#BF996B","#BF5841","A61C1C","#556354","#E68F0D","#8C948A","#495450","42423F","#323640","#5B6470","#8C94A1","#BDC7D6","DFE2FF","#FF0000","#FF950B","#2FA88C","#DEEB00","4B2C04","#0F3D48","#174C5B","#366774","#ECECE7","E96151","#3DBB7E","#A3CD39","#FBAC1D","#F96C1E","EE4036","#23363B","#A44F3F","#F8983D","#8D9151","BBC946","#4B5657","#969481","#D2C9B0","#F4E3C1","B6B835","#E8980C","#B1F543","#F2FF00","#FF5E00","59BBAB","#849696","#FEFFFB","#232D33","#17384D","FF972C","#555555","#7BB38E","#F4F1D7","#F8AB65","F15C4C","#1D3C42","#67BFAD","#F2EC99","#F2C48D","F25050","#334D5C","#45B29D","#EFC94C","#E27A3F","DF4949","#B8E1F2","#249AA7","#ABD25E","#F8C830","F1594A","#FDEDD0","#BCF1ED","#FF634D","#FD795B","FFF0AA","#FFFFFF","#E5E1D1","#52616D","#2C343B","C44741","#FFFFF1","#D5FF9B","#8FB87F","#5A7B6C","374E5A","#010340","#0E1E8C","#0003C7","#1510F0","1441F7","#002A4A","#17607D","#FFF1CE","#FF9311","E33200","#871E31","#CCC097","#9E9D7B","#687061","262626","#F16663","#F48D6C","#F2E07B","#8ABE9B","4A6D8B","#001F11","#204709","#0C8558","#FFD96A","FF4533","#1D1626","#F2E0BD","#BFAA8F","#8C786C","594C4C","#685D47","#913420","#1E2729","#C1D9C5","FEEFB1","#1D7561","#FC8448","#FF4138","#A8282B","38141B","#BF0633","#FF484E","#FF9273","#D1D0B4","E5ECED","#8E9E63","#E6DBB0","#F5EED7","#C4BCA0","176573","#665446","#809994","#AECCB6","#DEF2C4","E6683F","#3D0D26","#660A3E","#891C56","#B0276F","C93482","#082136","#00294D","#004B8D","#0068C4","2998FF","#3C4631","#9A746F","#F8A2AB","#F1C6B3","EAE9C0","#FF534E","#FFD7AC","#BED194","#499989","176785","#006D80","#BDA44D","#3C2000","#84CECC","78A419","#352C2B","#3C555C","#9E9657","#FFEBCD","CD5510","#2C3E50","#FC4349","#6DBCDB","#D7DADB","FFFFFF","#523631","#D1BE91","#605E3A","#4D462F","592F39","#18293B","#5B5A56","#F2DEA0","#D0B580","FFFBFF","#C8DBB6","#ECEBB7","#CCC68A","#B8B165","827A5D ","#7DA88C","#EBE9A0","#BED24B","#859132","35323C","#E8574C","#F27B29","#E6A51B","#D9CC3C","399977","#324032","#B7C22C","#FFFFE1","#22A8B5","2A3F42","#B3A589","#FFB896","#FFF9B1","#9AB385","11929E","#272433","#343F4F","#3D6066","#77994D","B2D249","#250701","#6D4320","#B0925F","#E7DEC0","82ABB8","#023550","#028A9E","#04BFBF","#EFEFEF","FF530D","#594732","#40342A","#7A422E","#D4CA9A","EDE5AE","#013C4D","#BA5B22","#DB913C","#F0B650","FAD46B","#143840","#5C6B63","#A69E89","#E0C297","D96523","#3FB8AF","#7FC7AF","#DAD8A7","#FFB38B","FF3F34","#CA3995","#F58220","#FFDF05","#BED73D","61BC46","#FFE1D0","#FFBFB4","#FF837E","#FF4242","BF1616","#C4EEFF","#7BA32D","#094201","#A41717","C48726","#001325","#187072","#90BD90","#D7D8A2","F2E4C2","#1A4F63","#068587","#6FB07F","#FCB03C","FC5B3F","#97B350","#333230","#736D61","#BAAB90","FFE5BA","#403D33","#807966","#CCC2A3","#8C0000","590000","#5F8A42","#86AD59","#F6FAA1","#F28410","D66011","#BF355D","#ED8168","#FAB66A","#F2DC86","83BFA1","#E1F03E","#FFBA14","#DB3A0F","#A1003D","630024","#212226","#45433F","#687067","#BDBB99","F0EAC3","#FE4365","#FC9D9A","#F9CDAD","#C8C8A9","83AF9B","#293B47","#5F7A87","#FFFFFF","#CBFF48","00ADA9","#282A33","#697371","#FFE7A6","#F5BA52","FA8000","#0C304A","#2B79A1","#F3F4F1","#85A71E","BFD841","#008B83","#4DAE83","#A0AE79","#FFE499","FF665E","#5D7359","#E0D697","#D6AA5C","#8C5430","661C0E","#324452","#97BDBF","#F2DFBB","#F28705","BF3604","#EEEFB9","#6ACFAE","#369C93","#232928","B03831","#332F45","#015770","#2A8782","#9FD6AE","FFFED2","#2B2830","#5C504F","#ABAB8E","#D9D7A3","C7BE88","#DC941B","#EDC266","#B6952C","#E1D3A6","E9A119","#00305A","#00448D","#0074D9","#4192D9","7ABAF2","#344459","#485F73","#5DA6A6","#A9D9CB","F2EAD0","#060719","#4D1B2F","#9E332E","#EB6528","FC9D1C","#96CEB4","#FFEEAD","#FF6F69","#FFCC5C","AAD8B0","#05F2F2","#04BFBF","#EEF1D9","#A60201","7E100E","#E6F1F5","#636769","#AAB3B6","#6E7476","4B4E50","#DA0734","#F1A20D","#4AABB1","#FCF3E7","3F1833","#202D44","#FC4349","#6DBCDB","#D7DADB","FFFFFF","#CC3B37","#398899","#FFFCE8","#FF857F","CCC1A3","#5DBEA9","#EFEDDF","#EF7247","#4E3F35","D1CBBA","#FFC62D","#E49400","#DD5200","#EFE38A","91B166","#B67D14","#F2921F","#F0B23E","#A62409","441208","#C71B1B","#D6BA8A","#017467","#E08F23","0B0D0C","#474143","#A69E9D","#E7E2DA","#FFFFFF","E7E8E7","#435772","#2DA4A8","#FEAA3A","#FD6041","CF2257","#6DD19D","#99E89D","#D0E8A1","#FFF9C0","D40049","#FAF1D5","#DEC9AC","#CCA18B","#11282D","A5C4BB","#000000","#141414","#1C1919","#1A1716","24201F","#D5D8DD","#5CA2BE","#135487","#2A4353","989DA4","#73161E","#BF0F30","#BFB093","#037F8C","0A2140","#195962","#F56F6C","#FFFFFF","#252932","191C21","#F8EFB6","#FEBAC5","#6CD1EA","#FACFD7","C2EAE9","#91D6BC","#768C6A","#755F31","#B37215","FFBA4B","#F2E6BB","#DD4225","#202724","#63BD99","F8FDD8","#762B1B","#807227","#CCBF7A","#FFEF98","60B0A1","#707864","#C1D74E","#F5FF7C","#DFE6B4","A6B89C","#FFF3D2","#97B48F","#E87657","#FF9B6F","E8D495","#33262E","#733230","#CC5539","#E6D27F","86A677","#122430","#273E45","#FFFCE2","#EBD2B5","E63531","#30394F","#FF434C","#6ACEEB","#EDE8DF","FFFBED","#0A3A4A","#196A73","#32A6A6","#A1BF36","C8D94A","#FFF7CC","#CCC28F","#70995C","#33664D","142933","#43464D","#9197A6","#D3DCF2","#7690CF","48577D","#DFE0AF","#A4BAA2","#569492","#41505E","383245","#B52841","#FFC051","#FF8939","#E85F4D","590051","#473C35","#A36D5C","#9C968B","#D9CEAD","8A866A","#DB4C39","#2D3638","#109489","#44D487","D0DB86","#6F8787","#AEC2AE","#E6DFAE","#B0B57B","888F51","#C8385A","#FFCF48","#ECEABE","#1FCECB","1CA9C9","#42282E","#75A48B","#D9CFB0","#DC9B74","D6665A","#362F2D","#4C4C4C","#94B73E","#B5C0AF","FAFDF2","#98293A","#B14A58","#C86C6B","#DE9D76","EFC77F","#C1D301","#76AB01","#0E6A00","#083500","042200","#453F22","#7A6B26","#CCAD5C","#A1191F","4E1716","#541E32","#8E3557","#88A33E","#C2BD86","F7F2B2","#2B1B2E","#54344D","#FFFFD6","#B89E95","6E444F","#6EC1A5","#9FBEA6","#F5D3A3","#FF9F88","FB7878","#2F252C","#D3CCB2","#99AD93","#6E6751","5C3122","#BE333F","#F2E9CE","#C8C5B1","#939F88","307360","#F0F1F2","#232625","#647362","#B3D929","D2D9B8","#FA2B31","#FFBF1F","#FFF146","#ABE319","00C481","#09455C","#527E7C","#F5FFCC","#E0EB6E","C4D224","#F2DA91","#F2B950","#F29D35","#D96704","BF4904","#A2CFA5","#E0E7AB","#F5974E","#E96B56","D24344","#150033","#310D42","#5C2445","#AB6946","FFCE4C","#23A38F","#B7C11E","#EFF1C2","#F0563D","2E313D","#FF2468","#E0D4B1","#FFFFE3","#00A5A6","005B63","#65A683","#218777","#3F585F","#47384D","F53357","#000623","#28475C","#4A6C74","#8BA693","F0E3C0","#E65322","#D19552","#B8BF73","#B6DB83","FFF991","#112F41","#068587","#6FB07F","#FCB03C","FC5B3F","#C89B41","#A16B2B","#77312B","#1C2331","152C52","#C24366","#D9C099","#FFF8D8","#A8E0BA","00ADA7","#CC0000","#006600","#FFFFEC","#9C9178","6C644F","#3D0319","#720435","#C1140E","#FC5008","32241B","#CFC7A4","#5A9E94","#005275","#002344","A38650","#FFEBC3","#CC3A00","#FF3600","#FF851B","800C00","#EFC164","#F3835D","#F35955","#286275","00434C","#E9F29D","#B7C29D","#878E8F","#67617A","51456B","#445859","#03A696","#49C4BE","#F1F2E4","FF7746","#FA726C","#FFD794","#BAD174","#3BA686","5F6F8C","#4D2B1F","#635D61","#7992A2","#97BFD5","BFDCF5","#CC4D00","#E6CF73","#668059","#264D4D","00CCB3","#4385F5","#DC4437","#FCBE1F","#109D59","FFFFFF","#271F2E","#A4A680","#F2EBC9","#D9B166","A66B38","#0B2C3C","#FF6666","#DADFE1","#FFFFFF","444444","#CFF09E","#A8DBA8","#79BD9A","#3B8686","0B486B","#302B26","#A6B827","#EDE9DD","#98D3D4","594E7A","#4B0505","#720707","#BFB694","#004659","00292B","#B52C38","#EBD1B0","#536682","#D9964B","DE6846","#F2F1DF","#F2B705","#F2C84B","#BF820F","734002","#26140C","#3D2216","#784E3D","#AB8574","D6BCB1","#26221D","#8C2C0F","#E6E5B8","#BFB38D","402D1F","#1F8181","#F2BC79","#F28972","#BF1B39","730240","#002635","#013440","#AB1A25","#D97925","EFE7BE","#8EC447","#FFFFFF","#96D3D4","#636466","2D2D2E","#2D1E1E","#4B3C37","#96A576","#CDE196","FFFFBE","#F06060","#FA987D","#F7F2CB","#72CCA7","10A296","#1D8281","#44BF87","#FBD258","#F29A3F","DB634F","#DEDE91","#EF9950","#F34E52","#C91452","492449","#6D8EAD","#1F3447","#1A0B07","#362416","CFCDB4","#00CD73","#008148","#2D9668","#3ECD8E","004E2C","#3D8080","#628282","#858383","#A38282","C28080","#475159","#839795","#B2BDB7","#CCC9C0","F2F2F2","#0E6870","#C6B599","#C65453","#FFDDB4","EDAA7D","#CEF0B7","#A8DBA8","#79BD9A","#3B8686","0B486B","#292C44","#FF5349","#F0F0F1","#18CDCA","4F80E1","#272A2B","#383737","#473B39","#692B28","940500","#D6C274","#DB9E46","#25706B","#3D2423","AB362E","#FFA68F","#FF4867","#FFF9C8","#B5EBB9","18B29D","#A1A16A","#727D59","#366353","#133C40","03212E","#D45354","#A9DC3A","#2FCAD8","#818B85","CDCDC1","#F14B6A","#3D3C3E","#22BDAF","#BAD7D4","F4F4F4","#FFE2C5","#FFEEDD","#FFDDAA","#FFC484","FFDD99","#9FFF4A","#1ABF93","#087363","#004040","2F1933","#FFDB97","#B28F4E","#FFFDFB","#466CB2","97BBFF","#991C00","#E09A25","#FFFCDB","#008B83","262B30","#44281A","#00ACAE","#F5EFD5","#F37606","EE4717","#FF5952","#FCEEC9","#96D6D9","#4FAAC9","176075","#5C4B51","#8CBEB2","#F2EBBF","#A5C88F","EF847B","#105F73","#F7F3B2","#C6CC33","#F28322","CC5404","#137072","#56B292","#B7F5AB","#FBFFC0","BF223D","#E3F23E","#6C821C","#A6A53F","#E0E0AC","33302E","#00215E","#003CAA","#1967F7","#5E4000","AA7400","#273A3D","#54695C","#AD9970","#FFBF87","FF8F60","#FFAA00","#C2B93E","#808F5D","#576157","302F30","#BE1405","#F2DCAC","#AABEAA","#736E41","413C2D","#6B1229","#C76A61","#FAB99A","#F7D9B5","CCB1A7","#2D9993","#58B3A3","#83BFA3","#B0D9A8","FFFCB6","#334D5C","#45B29D","#EFC94C","#E27A3F","DF5A49","#F30B55","#010326","#012840","#54717F","F2E6CE","#2A3411","#73662C","#BC9847","#FFDFB2","6B0031","#637D74","#403D3A","#8C3B3B","#AB6937","D4A960","#010A26","#011640","#B6D6F2","#FFFFFF","E83338","#924847","#EB986C","#E4C678","#9C7885","372C2C","#022440","#3F95AA","#4EC6DE","#EAE2DF","F7572F","#2B1D2E","#323657","#076473","#54B087","D6F567","#052229","#004043","#BCC373","#E3FF55","D0D90C","#4C514A","#907A62","#879796","#755854","B09880","#1D2939","#1CAF9A","#FFFFFF","#EE4F4B","D1DC48","#004B67","#41CCB4","#FFEA95","#FF7C5D","C70151","#C0272D","#FCFBE7","#9FD3DA","#008C9A","05484F","#213130","#FF5E3D","#C9C83E","#FDFFF1","559398","#B1E4FC","#366D78","#39D5F1","#FFFFFF","D9FF03","#DECE6C","#FCF9B6","#BFE3B5","#5D826E","262E2B","#520A17","#668F91","#F5E6AC","#AB8E5B","52301C","#2D3032","#DD5F18","#FBA922","#F7F7F7","404333","#0C2538","#2B434F","#638270","#BCC98E","EDE059","#E85066","#F28E76","#E6CEB0","#5A8C81","382837","#BF2633","#A6242F","#D9CEAD","#C0B18F","011C26","#002A4A","#17607D","#FFF1CE","#FF9311","E33200","#0A8B91","#485956","#C4B98F","#FFF9BC","EEDF2E","#B89A7B","#9BBAAC","#F2D649","#D95D50","DBDBDB","#BD7938","#8D4421","#643001","#532700","3A1C00","#E1E6FA","#C4D7ED","#ABC8E2","#375D81","183152","#2E4259","#F7483B","#ECF0F1","#03C8FA","737373","#364656","#5D6B74","#94A4A5","#F2F5E9","FF8C31","#3E5916","#93A605","#F28705","#F25C05","E5EFFA","#248077","#74AD8D","#C82754","#F7BB21","F9E2B7","#20736A","#8BD9CA","#B1D95B","#93A651","403E34","#D74B4B","#DCDDD8","#475F77","#354B5E","FFFFFF","#252F33","#415C4F","#869C80","#93C2CC","CEEAEE","#012840","#79C7D9","#9BF2EA","#497358","9DBF8E","#EE7E94","#F8B4C4","#C7CAC9","#D8505C","41424","#282828","#505050","#FFFFFF","#2DCEDB","F20000","#004358","#1F8A70","#BEDB39","#FF5347","FD7400","#470C3B","#802F56","#C0576F","#E38679","FFBD83","#573328","#B05A3A","#FF8548","#29332E","0F1B1C","#461F2D","#E1FFBB","#BAD47F","#849C23","52533F","#333A40","#4C5E5E","#ADD0E5","#CDE4FF","729EBF","#DE5605","#F7A035","#B1DEB5","#EFECCA","65ABA6","#76D6D2","#F9E270","#EF6F56","#F4EED8","596B56","#403E3F","#F2F2F2","#D9D9D9","#9DAABB","8C8C8C","#059E9A","#F4F2ED","#F5A243","#DB3E3B","585857","#FFBF41","#EE8943","#C02221","#FFF4D3","249CA9","#024E76","#39A6B2","#FCE138","#F5B824","F08106","#FF0067","#FF3D6A","#E7FF04","#9CFF00","56FF00","#003540","#0D3F40","#487360","#8FA671","F2D795","#FF493C","#FFFFFF","#B3ECEF","#31C4F5","ADEB41","#244358","#4A8B87","#7CBCAE","#F0D4AF","C5252B","#EA5930","#F8AF1E","#F5E5C0","#097380","372560","#A1DBB2","#FEE5AD","#FACA66","#F7A541","F45D4C","#2C4A47","#6C9A7F","#BB523D","#C89D11","81810B","#F0F1F2","#232625","#647362","#FF5629","D2D9B8","#7C9B5F","#B8D197","#E3FFF3","#9BDEC7","568F84","#E54E45","#DBC390","#F2F2EF","#13A3A5","403833","#77A7FB","#E57368","#FBCB43","#34B67A","FFFFFF","#001A2E","#8F0000","#FFFFFF","#8A874B","41594F","#312F40","#49A69C","#EFEAC5","#E89063","BF5656","#047C8C","#018B8D","#F3BF81","#F49B78","F1706D","#00303E","#7096AD","#C1D1DE","#FFF9EF","EC4911","#2D6891","#70A0BF","#F5EEDC","#DC4C1A","F0986C","#040002","#3D1309","#E8B96A","#BC5D15","5C0F00","#8B929C","#5E6070","#514454","#3B313D","FF2479","#142D58","#447F6E","#E1B65B","#C8782A","9E3E17","#22104D","#2D1E5E","#483A85","#7067AB","A49CFA","#919C86","#9E373E","#2B2E36","#D1B993","C45A3B","#332F45","#015770","#2A8782","#9FD6AE","FFFED2","#37C78F","#FEE293","#FF4D38","#CC2249","380C2A","#47282C","#8C8468","#C9B37F","#DBDAB7","C4C49C","#14191A","#2D2B21","#A69055","#CCB287","FFB88C","#F5E3CD","#696158","#B6A898","#877D71","504A43","#005151","#009393","#F56200","#454445","969692","#D95F47","#FFF2C1","#80A894","#106153","072C36","#9E352C","#E6E8A9","#93C28C","#2E5A5C","2B2623","#03013A","#334A94","#6B9EDF","#83C3F2","99E6FF","#372A26","#4D4D4D","#6DA0A7","#9ED5A8","C7F5FF","#03658C","#022E40","#F2B705","#F28705","F25C05","#FF3B16","#E87826","#E8BA4A","#80A272","003045","#00748E","#E3DFBB","#F4BA4D","#E3753C","DA3B3A","#25401E","#56732C","#84A63C","#B8D943","EAF2AC","#449BB5","#043D5D","#EB5055","#68C39F","FFFCF5","#108F97","#FF8B6B","#FFE39F","#16866D","103636","#1A4F63","#068F86","#6FD57F","#FCB03C","FC5B3F","#381C19","#472E29","#948658","#F0E99A","362E29","#D7E8F7","#BBD0E3","#9CB7CF","#6A8BAB","375D81","#0F1C28","#136972","#67BFA7","#F3CF5B","F07444","#FFFFFF","#4EA9A0","#969514","#FE9C03","FCDE8E","#2F2D30","#656566","#65537A","#51386E","2A2333","#4C2916","#F05A28","#FBAF3F","#38B449","FFFFFF","#132537","#006C80","#EBCAB8","#FE8315","FA3113","#ECEEE1","#A8DACF","#F05B4F","#D8403A","221E1F","#00305A","#004B8C","#0074D9","#4192D9","7ABAF2","#72CF3F","#85FF00","#23E000","#2FB81B","00FF1C","#45CEEF","#FFF5A5","#FFD4DA","#99D2E4","D8CAB4","#FF5B00","#A1716C","#728296","#439AAB","00CABD","#EB6C2D","#D9C8A2","#939C80","#496158","232F38","#D94214","#FFF2C1","#80A894","#52736B","093844","#4D1B2F","#9E332E","#EB6528","#FC9D1C","FFCA50","#FFEEB0","#9AE8A4","#C7C12D","#F76245","ED1C43","#FFFAED","#D4DBFF","#879AC9","#242942","FF8800","#022840","#013440","#517360","#9DA67C","F2DC99","#331A0F","#519994","#BA4B3C","#EEDDAA","789F63","#577867","#EDCE82","#D68644","#AB3229","662845","#435A66","#88A6AF","#F5F2EB","#D9CDB8","424342","#FF8840","#958D4F","#737B55","#595540","513E38","#9D805A","#EBC99D","#FFE6C5","#9DCEEA","4B809E","#272D40","#364659","#55736D","#9DBF8E","D0D991","#23A38F","#B7C11E","#EFF1C2","#F0563D","2E313D","#98C000","#3D4C53","#EA2E49","#FFE11A","0CDBE8","#A20E30","#E93C4F","#DCDCD4","#ADBCC3","2D4255","#1C2640","#263357","#384C80","#4E6AB3","5979CD","#D94214","#FFF2C1","#80A894","#52736B","093844","#3B596A","#427676","#3F9A82","#A1CD73","ECDB60","#1E1E1F","#424143","#67666A","#807F83","CBC9CF","#E04946","#3BA686","#B6D15D","#FFD495","FA847E","#FFEBB0","#FFB05A","#F84322","#C33A1A","9F3818","#FFA136","#FF814A","#E6635A","#785D6B","534557","#CDCF91","#EBEACC","#D6D5B8","#6D7D80","41545E","#011526","#011C40","#4E8DA6","#F2EA79","F2B33D","#353230","#3F4E51","#7B8F70","#99B2BE","F6F4EA","#063559","#0D8C7F","#8FBF4D","#F2D13E","D95929","#158000","#199900","#20BF00","#24D900","29FF00","#0B0D0E","#137074","#7EB7A3","#F1DDBB","EC6766","#02151A","#043A47","#087891","#C8C8C8","B31D14","#59361F","#5C992E","#A3CC52","#E6E673","FF5933","#FE4365","#FC9D9A","#F9CDAD","#C8C8A9","83AF9B","#4B1E18","#F9E5C2","#BBB082","#829993","4F5D4E","#032843","#1F595B","#508C6D","#71A670","A6DB89","#191724","#4C4547","#8C594E","#D18952","FDB157","#191919","#182828","#60702D","#AAB232","E6FA87","#212A3F","#434F5B","#F2F2F2","#8AB839","2E2E2E","#004158","#026675","#038B8B","#F1EEC9","F09979","#023059","#3F7EA6","#F2F2F2","#D99E32","BF5E0A","#F21E52","#FFFFFF","#3D3B42","#0C6F73","63CFD4","#452743","#E7635E","#F8E9A8","#89E0AD","00928C","#FAAD63","#D1714D","#785E48","#39403B","3D1C24","#4C0016","#FFF7EB","#DCCEA7","#A17345","104F53","#BF2431","#F24150","#2A4557","#3B848C","EFF2E4","#3B3013","#8F6031","#E88833","#9C0C0A","FDF3C1","#1E2422","#88BEB1","#FF006D","#DAFFFF","718A94","#F1F4F7","#AF9F7B","#775E43","#40413C","251C17","#00182E","#0C6BA1","#D4D6D4","#FFFDEB","FF7500","#FFAB4A","#CCBAAB","#1E2129","#3D5E6E","47A3A3","#66B3A7","#C0D4B6","#EEF0BD","#F0563D","2C2F3B","#332525","#907465","#EDC5B5","#878C6D","63674A","#F04C16","#DBDBD0","#EDBD1F","#4CB09C","313B4A","#2B211D","#611C26","#C5003E","#8EB7A8","F1E4B7","#1A1F2B","#30395C","#4A6491","#85A5CC","D0E4F2","#03497E","#0596D5","#9DEBFC","#999999","FE4B28","#2F4159","#465E73","#88A649","#F2ECE4","D98841","#323A46","#22282F","#EB4A33","#FFFFFF","E9F0F5","#2C3E50","#FC4349","#6DBCDB","#D7DADB","FFFFFF","#F29727","#E05723","#B0382F","#982E4B","713045","#4D584A","#465943","#428552","#3E754E","4C694B","#47191C","#59574B","#829690","#B5B09A","E1E3CB","#1D5123","#B1C661","#FFDA68","#FE9257","F64448","#59323C","#260126","#F2EEB3","#BFAF80","8C6954","#4E0805","#9E0522","#FFF4D4","#B8C591","447622","#424862","#FB9A63","#BFC4D5","#F6FBF4","FEBC98","#FF2468","#E0D4B1","#FFFFE3","#00A5A6","005B63","#1C2F40","#4C6173","#8094A6","#D9D1BA","F2E9D8","#DFD7B7","#EB7707","#5C5445","#3B2323","9CBFC7","#262E3B","#9C8878","#CFCAAA","#FBF8FF","992435","#FFBC67","#DA727E","#AC6C82","#685C79","455C7B","#404A69","#516C8A","#8AC0DE","#FFFFFF","FFAC00","#485B61","#4B8C74","#74C476","#A4E66D","CFFC83","#A31180","#C42795","#DE52B4","#EA88CE","FFBFE5","#E64D2E","#FFF5F1","#7893AD","#576B9C","2D2A52","#BF0436","#8C0327","#590219","#F2CBA1","8C674C","#CF5B6F","#FFF8C8","#CAD9B1","#8FB3A0","648991","#341D44","#744D90","#BB8CDD","#3E4417","88904D","#00293E","#003D4E","#006269","#00918F","00BAB5","#43212E","#D9666F","#F2D57E","#A9A688","516057","#2A3B30","#ABFFD1","#EBFFF5","#9DFEFF","273B40","#A63343","#E65159","#F5E9DB","#F4F7CF","BAD984","#1BA68C","#54BFAC","#F2EDA7","#F2E530","D94625","#1A2A40","#3F7369","#F2DEA0","#CE5251","EA895E","#1E9382","#70A758","#EFF1C2","#F0563D","2E313D","#A991E8","#FFB4BB","#ACF7FF","#A2E891","FFEDAE","#225B66","#17A3A5","#8DBF67","#FCCB5F","FC6E59","#282624","#BFB7AA","#403D39","#807A71","ABA398","#334D5C","#45B29D","#EFC94C","#E27A3F","DF4949","#440008","#605521","#988432","#D9A54E","9E3711","#649670","#36291E","#69AD6C","#92E67C","C5FF84","#42342C","#738076","#B2B39B","#DFE5E1","294359","#1A3838","#3F7A51","#82A352","#D1C062","FFBE59","#7D8C22","#B3BF67","#F2E49B","#D9DFF4","6791BF","#8A7D6D","#2D2D38","#E86E48","#FFFFE8","9CC9C9","#CFC949","#FFF5BF","#A9E6C4","#6AB39F","665841","#A1172D","#FDFFBA","#A7DB9E","#275C57","1F1B19","#FF6C0D","#F29E00","#E6C10F","#44996F","216273","#2C3E50","#FA4248","#D7DADB","#6DBCDB","FFFFFF","#627369","#99B397","#E2F2C6","#91CCAD","376266","#04496E","#66CAFF","#A3FC7E","#70D44A","2C6B0F","#1BA68C","#97BF3F","#F2ECD8","#F2B035","F2522E","#A2D9B1","#7CBF9E","#F2F1B9","#8C8575","193741","#024959","#037E8C","#F2EFDC","#E74C30","363636","#212625","#9CA6A2","#D0D9D6","#BF0404","C2C6AF","#00FFFF","#00FF00","#FFFF00","#FF5100","FF007C","#212629","#CDCF19","#FFF77D","#96C4AB","CF2A56","#CFF9FF","#BFC7BB","#787051","#332730","57324F","#98CACB","#FDEFBE","#F0542B","#736E5B","ABA68E","#F2F1EB","#BFB9A4","#262222","#802A30","8C0303","#65356B","#AB434F","#C76347","#FFA24C","519183","#78BF82","#A4D17C","#CFD96C","#EBD464","FFD970","#806265","#FFA256","#F7DD77","#E0D054","ABA73C","#8F323C","#123943","#80BDDB","#4189AB","C98127","#683820","#8C9A89","#E7D6A2","#BEAA65","9A8234","#021B21","#032C36","#065F73","#E8DFD6","FF2A1D","#2D6C73","#3FA693","#B4D9CB","#9ABF49","C6D93B","#141F26","#2B4040","#405950","#A69E86","F2D9BB","#4A8279","#003330","#610400","#003B06","02730F","#69B5E1","#D4E4F5","#EAF2F8","#BEDBED","000000","#893660","#EF7261","#68D693","#A0D7E2","299CA8","#073A59","#2D9AA6","#F2E2DC","#F23322","A61B1B","#2A3A48","#3E6372","#B2D4DC","#FAFAFF","FF6900","#F3BD8D","#F1A280","#BE6D6B","#704A5B","3E263C","#1C2742","#3C91C7","#5A9ABE","#95C5DE","E0EEFB","#426261","#465A59","#577573","#739A97","9AC1C0","#002A4A","#17607D","#FFF1CE","#FF9311","D64700","#589373","#BFBD99","#F2D6B3","#C2512F","241E1E","#1F518B","#1488C8","#F7E041","#E2413E","B5292A","#549494","#E85649","#232C2E","#E6E8D2","706558","#392133","#FFECBE","#D9D098","#C4AB6D","AB7D3A","#F0F0F0","#1C1C1C","#A2FDF5","#1CCDC7","27EDDF","#011526","#025959","#027353","#03A678","03A696","#004358","#1F8A70","#BEDB39","#FFE11A","FD7400","#37465D","#F2F2F2","#9DC02E","#779324","051A37","#580022","#AA2C30","#FFBE8D","#487B80","011D24","#F9F9F9","#03A678","#E9EDEB","#F44647","00707F","#800000","#BF0000","#E2D6C2","#F6EDD8","FFFFFF","#F7F6AF","#1B2124","#D62822","#97D6A6","468263","#432852","#992255","#FF3D4C","#28656E","00968F","#444344","#52BBB2","#2B344D","#EE5555","F8F7EE","#45334A","#796B7D","#CCC4B0","#FFF1B5","FFA3A3","#5A4B53","#9C3C58","#DE2B5B","#D86A41","D2A825","#14151C","#0C242B","#297059","#84D66E","D1FB7A","#272D40","#364659","#55736D","#9DBF8E","D0D991","#23A38F","#B7C11E","#EFF1C2","#F0563D","2E313D","#2E064D","#80176B","#B356A1","#59580B","FFFF00","#CC3333","#FF9D33","#F7F7F0","#3EBBA7","00747A","#5C4B51","#8CBEB2","#F2EBBF","#F3B562","BD6060","#0D3E58","#1C848C","#19C0C2","#F3EDD6","DA6260","#022629","#2A5945","#FAFFED","#E6DCC0","B3371C","#F4FAC7","#7BAD8D","#FFB159","#F77F45","C2454E","#A2C1C6","#86B1B7","#AECBAD","#CFDCB0","D6E1D1","#B0DAFF","#325B80","#64B7FF","#586D80","5092CC","#0F808C","#6C8C26","#F2A71B","#F26A1B","D91818","#FFBC6C","#FE9F6C","#BD716E","#74495F","3B2C4D","#FF4D41","#F2931F","#E6CA21","#91B321","1E8C65","#302821","#453629","#5C4837","#8A735F","BDA895","#415457","#5F7B7F","#9ACCAF","#E6EBC4","F9F7C8","#474143","#A69E9D","#E7E2DA","#FFFFFF","E7E8E7","#805939","#BD9962","#E6CD7D","#578072","2D4B4D","#03588C","#1763A6","#419CA6","#54BF83","8DBF41","#00CCFF","#A1FCFF","#040438","#004878","C9FAFF","#534C64","#B7DECF","#F0F3D7","#7E858C","D96557","#7F7364","#CBB08E","#CBC1B7","#789DCB","646F7F","#5C2849","#A73E5C","#EC7263","#FE9551","FFD285","#FF0012","#FF7D00","#FFD900","#5BE300","0084B0","#F24C32","#F29471","#FCDFA6","#36B898","3D7585","#083157","#0A6C87","#459C97","#92CCA5","C9F0B1","#DC941B","#EDC266","#B6952C","#E1D3A6","E9A119","#323836","#BAD1B5","#DBE8CF","#F0F7E8","FFFEF5","#081724","#589494","#8EBBB4","#D0DCD0","F5EED2","#50781C","#9CAD1C","#EAF7E6","#40A5DE","0B5191","#537F79","#78A68F","#CBD49C","#FED457","CB252A","#F23C13","#CBAB78","#FFFFFF","#898373","1F1C17","#450003","#5C0002","#94090D","#D40D12","FFED75","#0770A2","#82D9F7","#FEFEFE","#AEC844","F36622","#30394F","#FF434C","#6ACEEB","#EDE8DF","0E6569","#FF6B6B","#556270","#C7F464","#4ECDC4","EDC8BB","#D9B500","#FFED9C","#BFCC85","#748F74","454545","#452E32","#A34B1B","#B5A187","#EDDF9A","A7CC31","#2C2B33","#596664","#909980","#CCC08D","FF8A00","#C21F1F","#FFFFFC","#E34446","#FFFFDB","E36D6F","#282828","#00AAB5","#C1C923","#F41C54","F5F0F0","#3A3F40","#202627","#151B1E","#EFF4FF","41444D","#DEBB73","#4D0017","#010000","#4D0F30","9A002F","#EB9328","#FFA754","#FFD699","#FFF5DC","4FA6B3","#025E73","#037F8C","#D9D59A","#D9BD6A","590202","#636266","#E0CEA4","#E8A579","#7D6855","42403E","#FF0000","#FF4000","#FF7F00","#FFBF00","FFFF00","#FFFFFF","#74ADA6","#1E5E6F","#241B1F","68A81E","#5A0532","#FF6745","#FFC861","#9DAE64","27404A","#ACCBBC","#467847","#E8E4C1","#A60303","730202","#5C4B51","#8CBEB2","#F2EBBF","#F3B562","F06060","#0D2557","#93A8C9","#FFFFFF","#F5DED5","558D96","#F53C4A","#565157","#10CFC8","#F2EEE7","F5D662","#FFD97B","#E65029","#A60027","#660033","191C26","#595408","#A6800D","#A66D03","#A63F03","730C02","#2E031F","#590424","#8C072B","#BF0A2B","DEEFC5","#E0C882","#A6874E","#BFA169","#D9B779","F2D399","#D88681","#A67673","#746566","#535A5D","324F54","#FC297D","#FB607A","#FDA286","#FDC188","FEE78A","#FFECA1","#B3B27F","#4C5E52","#2F3436","FFBE2C","#D93312","#B3AB82","#45735F","#394D47","2C3233","#324143","#6595A3","#C8E3E8","#FCFFED","B6C28B","#477984","#FEF5EB","#C03C44","#EEAA4D","313E4A","#334D5C","#45B29D","#EFC94C","#E27A3F","DF4949","#630B11","#33322F","#2A2927","#1E1D1C","000000","#D94214","#FFF2C1","#80A894","#52736B","093844","#051E21","#00302D","#856434","#F28C28","FFAD4E","#D7DADD","#DDDEE3","#E1E1E9","#EDEFF4","F2F3F8","#BF495E","#41A693","#F2EC9B","#D9CF48","D9583B","#067072","#14A589","#DECFA6","#BAAE8C","F94B06","#423A38","#47B8C8","#E7EEE2","#BDB9B1","D7503E","#730324","#DFE3E6","#B4C4D4","#8BA2BD","456382","#537374","#F9BD7F","#EBD7A5","#ADC9A5","5C9E99","#88B59E","#B6DEC8","#39464D","#C04229","ABD1AB","#11A7FC","#95D127","#F2E415","#FF8638","EE3551","#212640","#5D718C","#4B95A6","#60BFBF","EFF2D8","#D8A64D","#9B5422","#351411","#5B0D0D","991C11","#53324F","#668D6E","#F2E0A0","#F19B7A","F0756E","#DFE0AF","#A4BAA2","#569492","#41505E","383245","#7BBADE","#93DE7F","#FFED5D","#F29E4A","FF7050","#133800","#1B4F1B","#398133","#5C9548","93E036","#D9D7AD","#91A685","#FF6A00","#37485C","1C232E","#008767","#FFB27A","#FF6145","#AB2141","5E1638","#727B7F","#CCEAEA","#7A7556","#2E2125","44CACC","#FFFFED","#FF2C38","#FF9A3A","#FFF040","67D9FF","#007148","#60A859","#9BDA6A","#C7F774","F9FFEF","#092740","#45698B","#90B0CC","#F1FAFF","8FD36F","#E2FFA0","#7D8076","#FAFFED","#C2CCBE","8F7D70","#00736A","#00BC9F","#F1EEC7","#FEA301","F2561A","#26282E","#AD5138","#F7F7F7","#DDDAE0","8594AE","#1A191F","#35352F","#484042","#4E5252","E64D38","#49454A","#E69B02","#FAF4C6","#B1D631","324052","#5F1A2B","#1D2834","#6F8B78","#E4D49E","C96466","#012D3D","#38AD9E","#FFEB9E","#FF6867","D0DBED","#0D1F36","#104954","#1E9C89","#38CC85","60EB7B","#8C4E03","#9FA66A","#F2EC94","#F23005","8B0F03","#000001","#20201F","#E2E2E4","#590402","B80000","#344059","#465973","#F2D272","#A69460","595139","#33454C","#608F85","#B6E5CB","#8BAF95","54584E","#FBFEF6","#B7BFA4","#687F70","#1A3841","BF3847","#D7E836","#86FFC7","#FFB048","#E8366C","593BFF","#34A9FF","#5982DB","#665EB8","#684682","632E62","#004056","#2C858D","#74CEB7","#C9FFD5","FFFFCB","#BFB978","#84945C","#516967","#4D3130","281B24","#103B73","#20638C","#3786A6","#4EABBF","EBEFF2","#9FB1BF","#1D2D63","#1C5357","#1F6E56","196331","#FFEBBA","#C3BD91","#88947B","#4C3F3F","2A2727","#347373","#4EA6A6","#91D9D9","#FFFFFD","F2E205","#828948","#EFDFC2","#006971","#DC533E","840000","#000137","#29003F","#79003D","#D04D14","F89801","#370005","#4B0005","#5F0005","#730005","870005","#C3AE8D","#F25260","#2D5F73","#6BADC9","8FCED6","#9E1B36","#F7EDBA","#E69B3D","#EB3355","3D241D","#1D8281","#44BF87","#FBD258","#F29A3F","DB634F","#035C75","#1B808C","#31A6A8","#F3F1BC","F3AD14","#FF7500","#665130","#EBB643","#CEDAA8","668E84","#384D3A","#3E6653","#728053","#A68357","D97C71","#012326","#17455C","#E1CAAB","#FE8333","FA4913","#1A2944","#2DA7C7","#56ACBA","#98C4C9","CBD5D2","#BF3542","#CDC5BA","#EBE3D6","#3C3C3C","2E2E2E","#231921","#695F74","#BEB4CB","#EBEBF0","D2DCEB","#34373F","#686C75","#F3E9D0","#BEB7A7","8E867C","#661510","#D9351A","#F2C76F","#BF9727","204D3F","#3CFFEE","#24AABC","#356781","#2C3D51","1C1F24","#DA3537","#FFFCC4","#00585F","#6A6A61","2A2C2B","#AE3135","#D1AF87","#8C826B","#3D3C33","F2F0CE","#FF0894","#FF5E9F","#FF91A7","#FFB5CA","F5F0BA","#99878D","#323232","#646464","#7E4A5C","372129","#3FB8AF","#7FC7AF","#DAD8A7","#FFB38B","FF3F34","#402B3C","#6AA6A6","#D9CCA7","#F2B263","F26835","#6AA690","#F2BC1B","#F2DC99","#F29057","BF1F1F","#F4FAC7","#7BAD8D","#FFB158","#F77F45","C2454E","#E5533C","#F5E346","#93D06D","#50AC6A","227864","#39588A","#A9BDD7","#FFFFFF","#FFEADD","FFD0BB","#B0B595","#615F4F","#828567","#91A380","EAFFCD","#00427F","#0066BD","#66B5CC","#F0E4C5","D6C28F","#FF6313","#F9E4B3","#C29689","#74474B","45232E","#00585F","#009393","#FFFCC4","#C7C49B","EB0A00","#091840","#44A2FF","#F7F7EA","#B3CC63","4C6620","#5CBBE3","#FCF1BC","#5C8182","#383A47","B4F257","#9E9E9E","#E5E1D1","#E0393D","#253746","425563","#4D9453","#FFFFB1","#ADDE4E","#FF9D27","A62A16","#B70046","#FF850B","#FFEBC5","#109679","675A4C","#363636","#0599B0","#A4BD0A","#FFA615","FF2E00","#7D8077","#BBBFB2","#FAFFED","#E82A33","E3DEBC","#FD9F44","#FC5C65","#007269","#03A679","FAF0B9","#134B57","#81A489","#F1D8B5","#F2A054","C04D31","#946E49","#394042","#EDDBAC","#872A0C","BA8E3A","#404040","#024959","#037E8C","#FFFFFF","F24C27","#2A3342","#163C6E","#4E5F61","#E6A015","EDE7BE","#445060","#829AB5","#849E91","#C14543","D6D5D1","#8A9126","#B7BF5E","#FFE9C4","#F5B776","F58E45","#9B2D1E","#3C3A28","#78A080","#9BCD9E","FFFFAE","#FF6138","#FFFF9D","#BEEB9F","#79BD8F","00A388","#990000","#FF6600","#FF9900","#996633","CC9966","#DCE6DA","#B8CCBB","#98B3A5","#7A9994","62858C","#0B1C29","#3B7C8F","#73A5A3","#98C1B7","F0EBD2","#F6CB51","#E25942","#13A89E","#3F4953","F2E7DA","#282F36","#FFFEFC","#BDA21D","#BFBC5B","D2E098","#8C182D","#DE7140","#FCB95A","#FAE285","6A7349","#6B9100","#FFE433","#FF841F","#E03D19","A6001C","#FFEAA7","#D9D697","#9FC49F","#718C6A","543122","#CFF09E","#A8DBA8","#79BD9A","#3B8686","0B486B","#0C2233","#065471","#0A91AB","#FFC045","F2F2F2","#BEE8E0","#373C40","#2E2621","#73320B","FF5E00","#1B2C35","#A3BFC6","#FF005D","#222A30","293A42","#FF8400","#3B4044","#494948","#E6E1D8","F7F2E9","#6A482D","#518C86","#F6BF3D","#EF7C27","BF2424","#261C2B","#292B39","#226468","#608D80","829D8F","#B2AD9A","#110E00","#363226","#A9A695","ECE9D8","#1B1B26","#26394D","#286480","#13B3BF","A3FF57","#F2C2A7","#F5E5C5","#593D28","#422C21","93DEDB","#001028","#033140","#1E5A5B","#7BA78C","EBEDC6","#544E6E","#808CB0","#ABD1D9","#D9FFF7","DDF556","#323A45","#596677","#758194","#FFFFFF","E74C3C","#45291A","#AB926D","#DBD1BC","#4999C3","5FCBEC","#6B151D","#2E1615","#A8553A","#DB8F5A","F2C18E","#000623","#28475C","#4A6C74","#8BA693","F0E3B1","#60807B","#81B37A","#BCCC5F","#FFEE65","E64964","#FFFFFA","#A1A194","#5B605F","#464646","FF6600","#1E1B17","#577270","#9C9A79","#C7BDA1","580E0C","#452F27","#5E504A","#6B6865","#9BBAB2","B0FFED","#1B5257","#F7F6C3","#F28159","#CC5850","4F1C2E","#FAA51B","#BF511F","#2C445E","#2F6D82","5EE4EB","#BF3952","#59364A","#556D73","#D9D1A9","D95F5F","#024959","#037E8C","#F2EFDC","#E74C30","363636","#221A26","#544759","#A197A6","#F27405","D93D04","#C4A44A","#E6D399","#9AB8A9","#7C8A7F","4E4B44","#FFFEC8","#B1BF99","#5B604D","#39382B","26181E","#4E3C51","#21A68D","#3BBF9A","#F2E8B6","F25749","#102144","#1B325E","#254580","#3C63B0","5D8AEA","#2A3A48","#3E6372","#B2D4DC","#FAFAFF","FF4B00","#FFF1BF","#F20058","#FFAEAC","#000001","7D7A96","#FDFFC6","#F2F096","#FF0080","#DE0049","521218","#5B0E00","#FBB500","#FBD864","#807D1A","59233C","#1E1E1F","#424143","#67666A","#807F83","CBC9CF","#3C3658","#3EC8B7","#7CD0B4","#B9D8B1","F7E0AE","#FFFFFF","#99B75F","#D5DD98","#EBF4DB","D8D8D8","#248A8A","#C9FA58","#F9E555","#FAAC38","F2572A","#086B63","#77A490","#E2D8C1","#BFAE95","7C7159","#5C4B51","#8CBEB2","#F2EBBF","#A5C88F","EF847B","#17162F","#89346D","#C76058","#FFB248","E8C475","#6E8F4A","#65D9C5","#F2E7B6","#EDA430","AB3E2C","#30394F","#FF434C","#6ACEEB","#EDE8DF","0E6569","#8E1B13","#F9E4B3","#849689","#46464A","29232E","#686B30","#AB9A52","#E8BA67","#D68F4F","BA512E","#E54E45","#DBC390","#F2F2EF","#13A3A5","403833","#65BA99","#59A386","#F1DDBB","#D6C4A6","E74C3C","#A6FFBC","#4ACFAF","#00A995","#006161","003D4C","#33271E","#8B7653","#C8D9A0","#FDEE9D","233331","#048789","#503D2E","#D44D27","#E2A72E","EFEBC8","#E5FF1E","#A9D943","#75A660","#698070","494D4B","#2DEBA2","#91F57F","#EBAA69","#E70049","2B0027","#990000","#336699","#DDDDDD","#999999","333333","#F13A4B","#3D3C3E","#22BDAF","#F4F4F4","D7D7D7","#F53A59","#001D2D","#15A88C","#B7D9C8","F3F5F4"]};Ops.Color.ColorPalettes.prototype=new CABLES.Op;CABLES.OPS["31d33a1e-9a0a-49f7-8bc8-9e83ab71e23e"]={f:Ops.Color.ColorPalettes,objName:"Ops.Color.ColorPalettes"};Ops.Gl.Shader.BasicMaterial_v3=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={basicmaterial_frag:"{{MODULES_HEAD}}\n\nIN vec2 texCoord;\n\n#ifdef VERTEX_COLORS\nIN vec4 vertCol;\n#endif\n\n#ifdef HAS_TEXTURES\n    IN vec2 texCoordOrig;\n    #ifdef HAS_TEXTURE_DIFFUSE\n        UNI sampler2D tex;\n    #endif\n    #ifdef HAS_TEXTURE_OPACITY\n        UNI sampler2D texOpacity;\n   #endif\n#endif\n\n\n\nvoid main()\n{\n    {{MODULE_BEGIN_FRAG}}\n    vec4 col=color;\n\n\n    #ifdef HAS_TEXTURES\n        vec2 uv=texCoord;\n\n        #ifdef CROP_TEXCOORDS\n            if(uv.x<0.0 || uv.x>1.0 || uv.y<0.0 || uv.y>1.0) discard;\n        #endif\n\n        #ifdef HAS_TEXTURE_DIFFUSE\n            col=texture(tex,uv);\n\n            #ifdef COLORIZE_TEXTURE\n                col.r*=color.r;\n                col.g*=color.g;\n                col.b*=color.b;\n            #endif\n        #endif\n        col.a*=color.a;\n        #ifdef HAS_TEXTURE_OPACITY\n            #ifdef TRANSFORMALPHATEXCOORDS\n                uv=texCoordOrig;\n            #endif\n            #ifdef ALPHA_MASK_IR\n                col.a*=1.0-texture(texOpacity,uv).r;\n            #endif\n            #ifdef ALPHA_MASK_IALPHA\n                col.a*=1.0-texture(texOpacity,uv).a;\n            #endif\n            #ifdef ALPHA_MASK_ALPHA\n                col.a*=texture(texOpacity,uv).a;\n            #endif\n            #ifdef ALPHA_MASK_LUMI\n                col.a*=dot(vec3(0.2126,0.7152,0.0722), texture(texOpacity,uv).rgb);\n            #endif\n            #ifdef ALPHA_MASK_R\n                col.a*=texture(texOpacity,uv).r;\n            #endif\n            #ifdef ALPHA_MASK_G\n                col.a*=texture(texOpacity,uv).g;\n            #endif\n            #ifdef ALPHA_MASK_B\n                col.a*=texture(texOpacity,uv).b;\n            #endif\n            // #endif\n        #endif\n    #endif\n\n    {{MODULE_COLOR}}\n\n    #ifdef DISCARDTRANS\n        if(col.a<0.2) discard;\n    #endif\n\n    #ifdef VERTEX_COLORS\n        col*=vertCol;\n    #endif\n\n    outColor = col;\n}\n",basicmaterial_vert:"\n{{MODULES_HEAD}}\n\nOUT vec2 texCoord;\nOUT vec2 texCoordOrig;\n\nUNI mat4 projMatrix;\nUNI mat4 modelMatrix;\nUNI mat4 viewMatrix;\n\n#ifdef HAS_TEXTURES\n    UNI float diffuseRepeatX;\n    UNI float diffuseRepeatY;\n    UNI float texOffsetX;\n    UNI float texOffsetY;\n#endif\n\n#ifdef VERTEX_COLORS\n    in vec4 attrVertColor;\n    out vec4 vertCol;\n\n#endif\n\n\nvoid main()\n{\n    mat4 mMatrix=modelMatrix;\n    mat4 modelViewMatrix;\n\n    norm=attrVertNormal;\n    texCoordOrig=attrTexCoord;\n    texCoord=attrTexCoord;\n    #ifdef HAS_TEXTURES\n        texCoord.x=texCoord.x*diffuseRepeatX+texOffsetX;\n        texCoord.y=(1.0-texCoord.y)*diffuseRepeatY+texOffsetY;\n    #endif\n\n    #ifdef VERTEX_COLORS\n        vertCol=attrVertColor;\n    #endif\n\n    vec4 pos = vec4(vPosition, 1.0);\n\n    #ifdef BILLBOARD\n       vec3 position=vPosition;\n       modelViewMatrix=viewMatrix*modelMatrix;\n\n       gl_Position = projMatrix * modelViewMatrix * vec4((\n           position.x * vec3(\n               modelViewMatrix[0][0],\n               modelViewMatrix[1][0],\n               modelViewMatrix[2][0] ) +\n           position.y * vec3(\n               modelViewMatrix[0][1],\n               modelViewMatrix[1][1],\n               modelViewMatrix[2][1]) ), 1.0);\n    #endif\n\n    {{MODULE_VERTEX_POSITION}}\n\n    #ifndef BILLBOARD\n        modelViewMatrix=viewMatrix * mMatrix;\n\n        {{MODULE_VERTEX_MODELVIEW}}\n\n    #endif\n\n    // mat4 modelViewMatrix=viewMatrix*mMatrix;\n\n    #ifndef BILLBOARD\n        // gl_Position = projMatrix * viewMatrix * modelMatrix * pos;\n        gl_Position = projMatrix * modelViewMatrix * pos;\n    #endif\n}\n"};const n=e.inTrigger("render");const i=e.outTrigger("trigger");const r=e.outObject("shader",null,"shader");r.ignoreValueSerialize=true;e.toWorkPortsNeedToBeLinked(n);e.toWorkShouldNotBeChild("Ops.Gl.TextureEffects.ImageCompose",CABLES.OP_PORT_TYPE_FUNCTION);const s=e.patch.cgl;const a=new CGL.Shader(s,"basicmaterialnew",this);a.addAttribute({type:"vec3",name:"vPosition"});a.addAttribute({type:"vec2",name:"attrTexCoord"});a.addAttribute({type:"vec3",name:"attrVertNormal",nameFrag:"norm"});a.addAttribute({type:"float",name:"attrVertIndex"});a.setModules(["MODULE_VERTEX_POSITION","MODULE_COLOR","MODULE_BEGIN_FRAG","MODULE_VERTEX_MODELVIEW"]);a.setSource(t.basicmaterial_vert,t.basicmaterial_frag);r.setRef(a);n.onTriggered=x;const o=e.inValueSlider("r",Math.random());const l=e.inValueSlider("g",Math.random());const h=e.inValueSlider("b",Math.random());const u=e.inValueSlider("a",1);o.setUiAttribs({colorPick:true});const f=a.addUniformFrag("4f","color",o,l,h,u);a.uniformColorDiffuse=f;const c=e.inTexture("texture");let d=null;c.onChange=T;const m=e.inValueBool("colorizeTexture",false);const g=e.inValueBool("Vertex Colors",false);const p=e.inTexture("textureOpacity");let F=null;const A=e.inSwitch("Alpha Mask Source",["Luminance","R","G","B","A","1-A","1-R"],"Luminance");A.setUiAttribs({greyout:true});p.onChange=S;const C=e.inValueBool("Opacity TexCoords Transform",false);const _=e.inValueBool("Discard Transparent Pixels");const E=e.inValue("diffuseRepeatX",1),v=e.inValue("diffuseRepeatY",1),b=e.inValue("Tex Offset X",0),B=e.inValue("Tex Offset Y",0),D=e.inBool("Crop TexCoords",false);a.addUniformFrag("f","diffuseRepeatX",E);a.addUniformFrag("f","diffuseRepeatY",v);a.addUniformFrag("f","texOffsetX",b);a.addUniformFrag("f","texOffsetY",B);const y=e.inValueBool("billboard",false);A.onChange=y.onChange=_.onChange=C.onChange=D.onChange=g.onChange=m.onChange=I;e.setPortGroup("Color",[o,l,h,u]);e.setPortGroup("Color Texture",[c,g,m]);e.setPortGroup("Opacity",[p,A,_,C]);e.setPortGroup("Texture Transform",[E,v,b,B,D]);S();T();e.preRender=function(){a.bind();x()};function x(){if(!a)return;s.pushShader(a);a.popTextures();if(d&&c.get())a.pushTexture(d,c.get());if(F&&p.get())a.pushTexture(F,p.get());i.trigger();s.popShader()}function S(){if(p.get()){if(F!==null)return;a.removeUniform("texOpacity");a.define("HAS_TEXTURE_OPACITY");if(!F)F=new CGL.Uniform(a,"t","texOpacity")}else{a.removeUniform("texOpacity");a.removeDefine("HAS_TEXTURE_OPACITY");F=null}I()}function T(){if(c.get()){if(!a.hasDefine("HAS_TEXTURE_DIFFUSE"))a.define("HAS_TEXTURE_DIFFUSE");if(!d)d=new CGL.Uniform(a,"t","texDiffuse")}else{a.removeUniform("texDiffuse");a.removeDefine("HAS_TEXTURE_DIFFUSE");d=null}O()}function O(){const e=c.isLinked()||p.isLinked();E.setUiAttribs({greyout:!e});v.setUiAttribs({greyout:!e});b.setUiAttribs({greyout:!e});B.setUiAttribs({greyout:!e});m.setUiAttribs({greyout:!e});A.setUiAttribs({greyout:!p.get()});C.setUiAttribs({greyout:!p.get()});let t=true;t=c.get()&&!m.get();o.setUiAttribs({greyout:t});l.setUiAttribs({greyout:t});h.setUiAttribs({greyout:t})}function I(){a.toggleDefine("VERTEX_COLORS",g.get());a.toggleDefine("CROP_TEXCOORDS",D.get());a.toggleDefine("COLORIZE_TEXTURE",m.get());a.toggleDefine("TRANSFORMALPHATEXCOORDS",C.get());a.toggleDefine("DISCARDTRANS",_.get());a.toggleDefine("BILLBOARD",y.get());a.toggleDefine("ALPHA_MASK_ALPHA",A.get()=="A");a.toggleDefine("ALPHA_MASK_IALPHA",A.get()=="1-A");a.toggleDefine("ALPHA_MASK_IR",A.get()=="1-R");a.toggleDefine("ALPHA_MASK_LUMI",A.get()=="Luminance");a.toggleDefine("ALPHA_MASK_R",A.get()=="R");a.toggleDefine("ALPHA_MASK_G",A.get()=="G");a.toggleDefine("ALPHA_MASK_B",A.get()=="B");O()}};Ops.Gl.Shader.BasicMaterial_v3.prototype=new CABLES.Op;CABLES.OPS["ec55d252-3843-41b1-b731-0482dbd9e72b"]={f:Ops.Gl.Shader.BasicMaterial_v3,objName:"Ops.Gl.Shader.BasicMaterial_v3"};Ops.Array.PointArray.TransformArray3=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inTriggerButton("Transform"),c=e.inArray("Array",3),d=e.inFloat("Translate X"),m=e.inFloat("Translate Y"),g=e.inFloat("Translate Z"),p=e.inFloat("Scale X",1),F=e.inFloat("Scale Y",1),A=e.inFloat("Scale Z",1),C=e.inFloat("Rotation X"),_=e.inFloat("Rotation Y"),E=e.inFloat("Rotation Z"),v=e.outTrigger("Next"),b=e.outArray("Result",3);e.setPortGroup("Translation",[d,m,g]);e.setPortGroup("Scale",[p,F,A]);e.setPortGroup("Rotation",[C,_,E]);let B=[];let D=true;let y=vec3.create();let i=vec3.create();let x=vec3.create();let r=vec3.create();n.onTriggered=a;c.onChange=d.onChange=m.onChange=g.onChange=p.onChange=F.onChange=A.onChange=C.onChange=_.onChange=E.onChange=s;function s(){D=true}function a(){let t=c.get();if(!t){b.set(null);return}if(t.length/3%1!=0){e.setUiError("invalidelength","invalid array length!");b.set(null);return}else e.setUiError("invalidelength",null);if(D){B.length=t.length;const n=C.get();const i=_.get();const r=E.get();const s=p.get();const a=F.get();const o=A.get();const l=d.get();const h=m.get();const u=g.get();const f=n||i||r;for(let e=0;e<t.length;e+=3){B[e+0]=t[e+0]*s;B[e+1]=t[e+1]*a;B[e+2]=t[e+2]*o;B[e+0]=B[e+0]+l;B[e+1]=B[e+1]+h;B[e+2]=B[e+2]+u;if(f){vec3.set(y,B[e+0],B[e+1],B[e+2]);if(n!=0)vec3.rotateX(y,y,x,n*CGL.DEG2RAD);if(i!=0)vec3.rotateY(y,y,x,i*CGL.DEG2RAD);if(r!=0)vec3.rotateZ(y,y,x,r*CGL.DEG2RAD);B[e+0]=y[0];B[e+1]=y[1];B[e+2]=y[2]}}D=false;b.setRef(B)}v.trigger()}};Ops.Array.PointArray.TransformArray3.prototype=new CABLES.Op;CABLES.OPS["b18040d6-13d7-4f55-950f-3f95cafa4e90"]={f:Ops.Array.PointArray.TransformArray3,objName:"Ops.Array.PointArray.TransformArray3"};Ops.Gl.Meshes.SplineMesh_v2=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inTrigger("Render"),a=e.inArray("Points"),o=e.inBool("Tesselate Edges",false),i=e.inBool("Render Mesh",true),r=e.outTrigger("Next");const s=new CGL.Geometry("splinemesh_2");s.vertices=[];s.clear();let l=[];const h=e.patch.cgl;let u=new Float32Array;let f=new Float32Array;let c=new Float32Array;let d=new Float32Array;let m=null;let g=new Float32Array;const p=new Float32Array;const F=[];const A=[0,0,0];let C=new CGL.Mesh(h,s);C.addVertexNumbers=true;let _=true;o.onChange=a.onChange=()=>{_=true};n.onTriggered=v;let E=null;function v(){if(_)B();if(C&&i.get()){if(E!=h.getShader()){E=h.getShader();if(!E)return;if(E.getName()!="splinemesh_material")e.setUiError("nosplinemat","Splinemesh needs a SplineMeshMaterial!");else e.setUiError("nosplinemat");E=h.getShader()}if(A.length>0)C.render(E)}r.trigger()}function b(){A.length=0;const t=1;const n=-t;for(let e=0;e<l.length/3;e++){A.push(t,n,0,0,n,0,t,t,0,0,n,0,0,t,0,t,t,0)}s.vertices=A;if(!C)C=new CGL.Mesh(h,s);C.addVertexNumbers=true;C.setGeom(s);C.addVertexNumbers=true}function B(){const i=a.get();if(!i||i.length===0){C=null;return}if(i[0]&&i[0].length){const s=[];m=[];let n=0;for(let t=0;t<i.length;t++){for(let e=0;e<i[t].length/3;e++){m[(n-3)/3]=t;s[n++]=i[t][e*3+0];s[n++]=i[t][e*3+1];s[n++]=i[t][e*3+2]}}l=s}else{m=null;l=i}if(o.get())l=y(l);b();const t=l.length*6;let n=0;let e=0;let r=0;if(u.length!=t){u=new Float32Array(t);f=new Float32Array(t);c=new Float32Array(t);d=new Float32Array(t/3);g=new Float32Array(t/3);for(let e=0;e<t/3;e++)g[e]=e/(t/3)}for(let t=0;t<l.length/3;t++){if(m){if(t>1&&e!=m[t])r=0;else r=1;e=m[t]}else r=1;for(let e=0;e<6;e++){d[n/3]=r;for(let e=0;e<3;e++){u[n]=l[Math.max(0,t-1)*3+e];f[n]=l[(t+0)*3+e];c[n]=l[(t+1)*3+e];n++}}}C.setAttribute("spline",u,3);C.setAttribute("spline2",f,3);C.setAttribute("spline3",c,3);C.setAttribute("splineDoDraw",d,1);C.setAttribute("splineProgress",g,1);_=false}function D(e,t,n){return e+n*(t-e)}function y(t){let n=0;const i=.001;const r=1-i;const e=t.length*3-3;F.length=e;const s=[];if(m)s[0]=m[1];for(let e=0;e<t.length-3;e+=3){F[n++]=t[e+0];F[n++]=t[e+1];F[n++]=t[e+2];if(m)s[n/3]=m[e/3];F[n++]=D(t[e+0],t[e+3],i);F[n++]=D(t[e+1],t[e+4],i);F[n++]=D(t[e+2],t[e+5],i);if(m)s[n/3]=m[e/3];F[n++]=D(t[e+0],t[e+3],r);F[n++]=D(t[e+1],t[e+4],r);F[n++]=D(t[e+2],t[e+5],r);if(m)s[n/3]=m[e/3]}if(m)m=s;return F}};Ops.Gl.Meshes.SplineMesh_v2.prototype=new CABLES.Op;CABLES.OPS["287abf6c-5501-4bc9-a627-70ec3c3766d2"]={f:Ops.Gl.Meshes.SplineMesh_v2,objName:"Ops.Gl.Meshes.SplineMesh_v2"};Ops.Gl.GLTF.GltfScene_v3=function(){CABLES.Op.apply(this,arguments);const _=this;const l=_.attachments={inc_camera_js:"const gltfCamera = class\n{\n    constructor(gltf, node)\n    {\n        this.node = node;\n        this.name = node.name;\n        // console.log(gltf);\n        this.config = gltf.json.cameras[node.camera];\n\n        this.pos = vec3.create();\n        this.quat = quat.create();\n        this.vCenter = vec3.create();\n        this.vUp = vec3.create();\n        this.vMat = mat4.create();\n    }\n\n    updateAnim(time)\n    {\n        if (this.node && this.node._animTrans)\n        {\n            vec3.set(this.pos,\n                this.node._animTrans[0].getValue(time),\n                this.node._animTrans[1].getValue(time),\n                this.node._animTrans[2].getValue(time));\n\n            quat.set(this.quat,\n                this.node._animRot[0].getValue(time),\n                this.node._animRot[1].getValue(time),\n                this.node._animRot[2].getValue(time),\n                this.node._animRot[3].getValue(time));\n        }\n    }\n\n    start(time)\n    {\n        if (cgl.tempData.shadowPass) return;\n\n        this.updateAnim(time);\n        const asp = cgl.getViewPort()[2] / cgl.getViewPort()[3];\n\n        cgl.pushPMatrix();\n        // mat4.perspective(\n        //     cgl.pMatrix,\n        //     this.config.perspective.yfov*0.5,\n        //     asp,\n        //     this.config.perspective.znear,\n        //     this.config.perspective.zfar);\n\n        cgl.pushViewMatrix();\n        // mat4.identity(cgl.vMatrix);\n\n        // if(this.node && this.node.parent)\n        // {\n        //     console.log(this.node.parent)\n        // vec3.add(this.pos,this.pos,this.node.parent._node.translation);\n        // vec3.sub(this.vCenter,this.vCenter,this.node.parent._node.translation);\n        // mat4.translate(cgl.vMatrix,cgl.vMatrix,\n        // [\n        //     -this.node.parent._node.translation[0],\n        //     -this.node.parent._node.translation[1],\n        //     -this.node.parent._node.translation[2]\n        // ])\n        // }\n\n        // vec3.set(this.vUp, 0, 1, 0);\n        // vec3.set(this.vCenter, 0, -1, 0);\n        // // vec3.set(this.vCenter, 0, 1, 0);\n        // vec3.transformQuat(this.vCenter, this.vCenter, this.quat);\n        // vec3.normalize(this.vCenter, this.vCenter);\n        // vec3.add(this.vCenter, this.vCenter, this.pos);\n\n        // mat4.lookAt(cgl.vMatrix, this.pos, this.vCenter, this.vUp);\n\n        let mv = mat4.create();\n        mat4.invert(mv, this.node.modelMatAbs());\n\n        // console.log(this.node.modelMatAbs());\n\n        this.vMat = mv;\n\n        mat4.identity(cgl.vMatrix);\n        // console.log(mv);\n        mat4.mul(cgl.vMatrix, cgl.vMatrix, mv);\n    }\n\n    end()\n    {\n        if (cgl.tempData.shadowPass) return;\n        cgl.popPMatrix();\n        cgl.popViewMatrix();\n    }\n};\n",inc_gltf_js:'const CHUNK_HEADER_SIZE = 8;\n\nconst Gltf = class\n{\n    constructor()\n    {\n        this.json = {};\n        this.accBuffers = [];\n        this.meshes = [];\n        this.nodes = [];\n        this.shaders = [];\n        this.timing = [];\n        this.cams = [];\n        this.startTime = performance.now();\n        this.bounds = new CABLES.CG.BoundingBox();\n        this.loaded = Date.now();\n        this.accBuffersDelete = [];\n    }\n\n    getNode(n)\n    {\n        for (let i = 0; i < this.nodes.length; i++)\n        {\n            if (this.nodes[i].name == n) return this.nodes[i];\n        }\n    }\n\n    unHideAll()\n    {\n        for (let i = 0; i < this.nodes.length; i++)\n        {\n            this.nodes[i].unHide();\n        }\n    }\n};\n\nfunction Utf8ArrayToStr(array)\n{\n    if (window.TextDecoder) return new TextDecoder("utf-8").decode(array);\n\n    let out, i, len, c;\n    let char2, char3;\n\n    out = "";\n    len = array.length;\n    i = 0;\n    while (i < len)\n    {\n        c = array[i++];\n        switch (c >> 4)\n        {\n        case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:\n            // 0xxxxxxx\n            out += String.fromCharCode(c);\n            break;\n        case 12: case 13:\n            // 110x xxxx   10xx xxxx\n            char2 = array[i++];\n            out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F));\n            break;\n        case 14:\n            // 1110 xxxx  10xx xxxx  10xx xxxx\n            char2 = array[i++];\n            char3 = array[i++];\n            out += String.fromCharCode(((c & 0x0F) << 12) |\n                    ((char2 & 0x3F) << 6) |\n                    ((char3 & 0x3F) << 0));\n            break;\n        }\n    }\n\n    return out;\n}\n\nfunction readChunk(dv, bArr, arrayBuffer, offset)\n{\n    const chunk = {};\n\n    if (offset >= dv.byteLength)\n    {\n        op.log("could not read chunk...");\n        return;\n    }\n    chunk.size = dv.getUint32(offset + 0, le);\n\n    // chunk.type = new TextDecoder("utf-8").decode(bArr.subarray(offset+4, offset+4+4));\n    chunk.type = Utf8ArrayToStr(bArr.subarray(offset + 4, offset + 4 + 4));\n\n    if (chunk.type == "BIN\\0")\n    {\n        // console.log(chunk.size,arrayBuffer.length,offset);\n        // try\n        // {\n        chunk.dataView = new DataView(arrayBuffer, offset + 8, chunk.size);\n        // }\n        // catch(e)\n        // {\n        //     chunk.dataView = null;\n        //     console.log(e);\n        // }\n    }\n    else\n    if (chunk.type == "JSON")\n    {\n        const json = Utf8ArrayToStr(bArr.subarray(offset + 8, offset + 8 + chunk.size));\n\n        try\n        {\n            const obj = JSON.parse(json);\n            chunk.data = obj;\n            outGenerator.set(obj.asset.generator);\n        }\n        catch (e)\n        {\n        }\n    }\n    else\n    {\n        op.warn("unknown type", chunk.type);\n    }\n\n    return chunk;\n}\n\nfunction loadAnims(gltf)\n{\n    const uniqueAnimNames = {};\n\n    for (let i = 0; i < gltf.json.animations.length; i++)\n    {\n        const an = gltf.json.animations[i];\n\n        for (let ia = 0; ia < an.channels.length; ia++)\n        {\n            const chan = an.channels[ia];\n\n            const node = gltf.nodes[chan.target.node];\n            const sampler = an.samplers[chan.sampler];\n\n            const acc = gltf.json.accessors[sampler.input];\n            const bufferIn = gltf.accBuffers[sampler.input];\n\n            const accOut = gltf.json.accessors[sampler.output];\n            const bufferOut = gltf.accBuffers[sampler.output];\n\n            gltf.accBuffersDelete.push(sampler.output, sampler.input);\n\n            if (bufferIn && bufferOut)\n            {\n                let numComps = 1;\n                if (accOut.type == "VEC2")numComps = 2;\n                else if (accOut.type == "VEC3")numComps = 3;\n                else if (accOut.type == "VEC4")numComps = 4;\n                else op.warn("unknown accOut.type", accOut.type);\n\n                const anims = [];\n\n                uniqueAnimNames[an.name] = true;\n\n                for (let k = 0; k < numComps; k++)\n                {\n                    const newAnim = new CABLES.Anim();\n                    // newAnim.name=an.name;\n                    anims.push(newAnim);\n                }\n\n                if (sampler.interpolation === "LINEAR") {}\n                else if (sampler.interpolation === "STEP") for (let k = 0; k < numComps; k++) anims[k].defaultEasing = CABLES.EASING_ABSOLUTE;\n                else if (sampler.interpolation === "CUBICSPLINE") for (let k = 0; k < numComps; k++) anims[k].defaultEasing = CABLES.EASING_CUBICSPLINE;\n                else op.warn("unknown interpolation", sampler.interpolation);\n\n                // console.log(bufferOut)\n\n                // if there is no keyframe for time 0 copy value of first keyframe at time 0\n                if (bufferIn[0] !== 0.0)\n                    for (let k = 0; k < numComps; k++)\n                        anims[k].setValue(0, bufferOut[0 * numComps + k]);\n\n                // console.log(sampler.interpolation,bufferOut.length/numComps)\n\n                for (let j = 0; j < bufferIn.length; j++)\n                {\n                    maxTime = Math.max(bufferIn[j], maxTime);\n\n                    for (let k = 0; k < numComps; k++)\n                    {\n                        if (anims[k].defaultEasing === CABLES.EASING_CUBICSPLINE)\n                        {\n                            const idx = ((j * numComps) * 3 + k);\n\n                            const key = anims[k].setValue(bufferIn[j], bufferOut[idx + numComps]);\n                            key.bezTangIn = bufferOut[idx];\n                            key.bezTangOut = bufferOut[idx + (numComps * 2)];\n\n                            // console.log(an.name,k,bufferOut[idx+1]);\n                        }\n                        else\n                        {\n                            // console.log(an.name,k,bufferOut[j * numComps + k]);\n                            anims[k].setValue(bufferIn[j], bufferOut[j * numComps + k]);\n                        }\n                    }\n                }\n\n                node.setAnim(chan.target.path, an.name, anims);\n            }\n            else\n            {\n                op.warn("loadAmins bufferIn undefined ", bufferIn === undefined);\n                op.warn("loadAmins bufferOut undefined ", bufferOut === undefined);\n                op.warn("loadAmins ", sampler, accOut);\n                op.warn("loadAmins num accBuffers", gltf.accBuffers.length);\n                op.warn("loadAmins num accessors", gltf.json.accessors.length);\n            }\n        }\n    }\n\n    gltf.uniqueAnimNames = uniqueAnimNames;\n\n    outAnims.setRef(Object.keys(uniqueAnimNames));\n}\n\nfunction loadCams(gltf)\n{\n    if (!gltf || !gltf.json.cameras) return;\n\n    gltf.cameras = gltf.cameras || [];\n\n    for (let i = 0; i < gltf.nodes.length; i++)\n    {\n        if (gltf.nodes[i].hasOwnProperty("camera"))\n        {\n            const cam = new gltfCamera(gltf, gltf.nodes[i]);\n            gltf.cameras.push(cam);\n        }\n    }\n}\n\nfunction loadAfterDraco()\n{\n    if (!window.DracoDecoder)\n    {\n        setTimeout(() =>\n        {\n            loadAfterDraco();\n        }, 100);\n    }\n\n    reloadSoon();\n}\n\nfunction parseGltf(arrayBuffer)\n{\n    let j = 0, i = 0;\n\n    const gltf = new Gltf();\n    gltf.timing.push(["Start parsing", Math.round((performance.now() - gltf.startTime))]);\n\n    if (!arrayBuffer) return;\n    const byteArray = new Uint8Array(arrayBuffer);\n    let pos = 0;\n\n    // var string = new TextDecoder("utf-8").decode(byteArray.subarray(pos, 4));\n    const string = Utf8ArrayToStr(byteArray.subarray(pos, 4));\n    pos += 4;\n    if (string != "glTF") return;\n\n    gltf.timing.push(["dataview", Math.round((performance.now() - gltf.startTime))]);\n\n    const dv = new DataView(arrayBuffer);\n    const version = dv.getUint32(pos, le);\n    pos += 4;\n    const size = dv.getUint32(pos, le);\n    pos += 4;\n\n    outVersion.set(version);\n\n    const chunks = [];\n    gltf.chunks = chunks;\n\n    chunks.push(readChunk(dv, byteArray, arrayBuffer, pos));\n    pos += chunks[0].size + CHUNK_HEADER_SIZE;\n    gltf.json = chunks[0].data;\n\n    gltf.cables = {\n        "fileUrl": inFile.get(),\n        "shortFileName": CABLES.basename(inFile.get())\n    };\n\n    outJson.set(gltf.json);\n    outExtensions.set(gltf.json.extensionsUsed || []);\n\n    let ch = readChunk(dv, byteArray, arrayBuffer, pos);\n    while (ch)\n    {\n        chunks.push(ch);\n        pos += ch.size + CHUNK_HEADER_SIZE;\n        ch = readChunk(dv, byteArray, arrayBuffer, pos);\n    }\n\n    gltf.chunks = chunks;\n\n    const views = chunks[0].data.bufferViews;\n    const accessors = chunks[0].data.accessors;\n\n    gltf.timing.push(["Parse buffers", Math.round((performance.now() - gltf.startTime))]);\n\n    if (gltf.json.extensionsUsed && gltf.json.extensionsUsed.indexOf("KHR_draco_mesh_compression") > -1)\n    {\n        if (!window.DracoDecoder)\n        {\n            op.setUiError("gltfdraco", "GLTF draco compression lib not found / add draco op to your patch!");\n\n            loadAfterDraco();\n            return gltf;\n        }\n        else\n        {\n            gltf.useDraco = true;\n        }\n    }\n\n    op.setUiError("gltfdraco", null);\n    // let accPos = (view.byteOffset || 0) + (acc.byteOffset || 0);\n\n    if (views)\n    {\n        for (i = 0; i < accessors.length; i++)\n        {\n            const acc = accessors[i];\n            const view = views[acc.bufferView];\n\n            let numComps = 0;\n            if (acc.type == "SCALAR")numComps = 1;\n            else if (acc.type == "VEC2")numComps = 2;\n            else if (acc.type == "VEC3")numComps = 3;\n            else if (acc.type == "VEC4")numComps = 4;\n            else if (acc.type == "MAT4")numComps = 16;\n            else console.error("unknown accessor type", acc.type);\n\n            //   const decoder = new decoderModule.Decoder();\n            //   const decodedGeometry = decodeDracoData(data, decoder);\n            //   // Encode mesh\n            //   encodeMeshToFile(decodedGeometry, decoder);\n\n            //   decoderModule.destroy(decoder);\n            //   decoderModule.destroy(decodedGeometry);\n\n            // 5120 (BYTE)\t1\n            // 5121 (UNSIGNED_BYTE)\t1\n            // 5122 (SHORT)\t2\n\n            if (chunks[1].dataView)\n            {\n                if (view)\n                {\n                    const num = acc.count * numComps;\n                    let accPos = (view.byteOffset || 0) + (acc.byteOffset || 0);\n                    let stride = view.byteStride || 0;\n                    let dataBuff = null;\n\n                    if (acc.componentType == 5126 || acc.componentType == 5125) // 4byte FLOAT or INT\n                    {\n                        stride = stride || 4;\n\n                        const isInt = acc.componentType == 5125;\n                        if (isInt)dataBuff = new Uint32Array(num);\n                        else dataBuff = new Float32Array(num);\n\n                        for (j = 0; j < num; j++)\n                        {\n                            if (isInt) dataBuff[j] = chunks[1].dataView.getUint32(accPos, le);\n                            else dataBuff[j] = chunks[1].dataView.getFloat32(accPos, le);\n\n                            if (stride != 4 && (j + 1) % numComps === 0)accPos += stride - (numComps * 4);\n                            accPos += 4;\n                        }\n                    }\n                    else if (acc.componentType == 5123) // UNSIGNED_SHORT\n                    {\n                        stride = stride || 2;\n\n                        dataBuff = new Uint16Array(num);\n\n                        for (j = 0; j < num; j++)\n                        {\n                            dataBuff[j] = chunks[1].dataView.getUint16(accPos, le);\n\n                            if (stride != 2 && (j + 1) % numComps === 0) accPos += stride - (numComps * 2);\n\n                            accPos += 2;\n                        }\n                    }\n                    else if (acc.componentType == 5121) // UNSIGNED_BYTE\n                    {\n                        stride = stride || 1;\n\n                        dataBuff = new Uint8Array(num);\n\n                        for (j = 0; j < num; j++)\n                        {\n                            dataBuff[j] = chunks[1].dataView.getUint8(accPos, le);\n\n                            if (stride != 1 && (j + 1) % numComps === 0) accPos += stride - (numComps * 1);\n\n                            accPos += 1;\n                        }\n                    }\n\n                    else\n                    {\n                        console.error("unknown component type", acc.componentType);\n                    }\n\n                    gltf.accBuffers.push(dataBuff);\n                }\n                else\n                {\n                    // console.log("has no dataview");\n                }\n            }\n        }\n    }\n\n    gltf.timing.push(["Parse mesh groups", Math.round((performance.now() - gltf.startTime))]);\n\n    gltf.json.meshes = gltf.json.meshes || [];\n\n    if (gltf.json.meshes)\n    {\n        for (i = 0; i < gltf.json.meshes.length; i++)\n        {\n            const mesh = new gltfMeshGroup(gltf, gltf.json.meshes[i]);\n            gltf.meshes.push(mesh);\n        }\n    }\n\n    gltf.timing.push(["Parse nodes", Math.round((performance.now() - gltf.startTime))]);\n\n    for (i = 0; i < gltf.json.nodes.length; i++)\n    {\n        if (gltf.json.nodes[i].children)\n            for (j = 0; j < gltf.json.nodes[i].children.length; j++)\n            {\n                gltf.json.nodes[gltf.json.nodes[i].children[j]].isChild = true;\n            }\n    }\n\n    for (i = 0; i < gltf.json.nodes.length; i++)\n    {\n        const node = new gltfNode(gltf.json.nodes[i], gltf);\n        gltf.nodes.push(node);\n    }\n\n    for (i = 0; i < gltf.nodes.length; i++)\n    {\n        const node = gltf.nodes[i];\n\n        if (!node.children) continue;\n        for (let j = 0; j < node.children.length; j++)\n        {\n            gltf.nodes[node.children[j]].parent = node;\n        }\n    }\n\n    for (i = 0; i < gltf.nodes.length; i++)\n    {\n        gltf.nodes[i].initSkin();\n    }\n\n    needsMatUpdate = true;\n\n    gltf.timing.push(["load anims", Math.round((performance.now() - gltf.startTime))]);\n\n    if (gltf.json.animations) loadAnims(gltf);\n\n    gltf.timing.push(["load cameras", Math.round((performance.now() - gltf.startTime))]);\n\n    if (gltf.json.cameras) loadCams(gltf);\n\n    gltf.timing.push(["finished", Math.round((performance.now() - gltf.startTime))]);\n    return gltf;\n}\n',inc_mesh_js:'let gltfMesh = class\n{\n    constructor(name, prim, gltf, finished)\n    {\n        this.POINTS = 0;\n        this.LINES = 1;\n        this.LINE_LOOP = 2;\n        this.LINE_STRIP = 3;\n        this.TRIANGLES = 4;\n        this.TRIANGLE_STRIP = 5;\n        this.TRIANGLE_FAN = 6;\n\n        this.test = 0;\n        this.name = name;\n        this.submeshIndex = 0;\n        this.material = prim.material;\n        this.mesh = null;\n        this.geom = new CGL.Geometry("gltf_" + this.name);\n        this.geom.verticesIndices = [];\n        this.bounds = null;\n        this.primitive = 4;\n        if (prim.hasOwnProperty("mode")) this.primitive = prim.mode;\n\n        if (prim.hasOwnProperty("indices")) this.geom.verticesIndices = gltf.accBuffers[prim.indices];\n\n        gltf.loadingMeshes = gltf.loadingMeshes || 0;\n        gltf.loadingMeshes++;\n\n        this.materialJson =\n            this._matPbrMetalness =\n            this._matPbrRoughness =\n            this._matDiffuseColor = null;\n\n        if (gltf.json.materials)\n        {\n            if (this.material != -1) this.materialJson = gltf.json.materials[this.material];\n\n            if (this.materialJson && this.materialJson.pbrMetallicRoughness)\n            {\n                if (!this.materialJson.pbrMetallicRoughness.hasOwnProperty("baseColorFactor"))\n                {\n                    this._matDiffuseColor = [1, 1, 1, 1];\n                }\n                else\n                {\n                    this._matDiffuseColor = this.materialJson.pbrMetallicRoughness.baseColorFactor;\n                }\n\n                this._matDiffuseColor = this.materialJson.pbrMetallicRoughness.baseColorFactor;\n\n                if (!this.materialJson.pbrMetallicRoughness.hasOwnProperty("metallicFactor"))\n                {\n                    this._matPbrMetalness = 1.0;\n                }\n                else\n                {\n                    this._matPbrMetalness = this.materialJson.pbrMetallicRoughness.metallicFactor || null;\n                }\n\n                if (!this.materialJson.pbrMetallicRoughness.hasOwnProperty("roughnessFactor"))\n                {\n                    this._matPbrRoughness = 1.0;\n                }\n                else\n                {\n                    this._matPbrRoughness = this.materialJson.pbrMetallicRoughness.roughnessFactor || null;\n                }\n            }\n        }\n\n        if (gltf.useDraco && prim.extensions.KHR_draco_mesh_compression)\n        {\n            const view = gltf.chunks[0].data.bufferViews[prim.extensions.KHR_draco_mesh_compression.bufferView];\n            const num = view.byteLength;\n            const dataBuff = new Int8Array(num);\n            let accPos = (view.byteOffset || 0);// + (acc.byteOffset || 0);\n            for (let j = 0; j < num; j++)\n            {\n                dataBuff[j] = gltf.chunks[1].dataView.getInt8(accPos, le);\n                accPos++;\n            }\n\n            const dracoDecoder = window.DracoDecoder;\n            dracoDecoder.decodeGeometry(dataBuff.buffer, (geometry) =>\n            {\n                const geom = new CGL.Geometry("draco mesh " + name);\n\n                for (let i = 0; i < geometry.attributes.length; i++)\n                {\n                    const attr = geometry.attributes[i];\n\n                    if (attr.name === "position") geom.vertices = attr.array;\n                    else if (attr.name === "normal") geom.vertexNormals = attr.array;\n                    else if (attr.name === "uv") geom.texCoords = attr.array;\n                    else if (attr.name === "color") geom.vertexColors = this.calcVertexColors(attr.array);\n                    else if (attr.name === "joints") geom.setAttribute("attrJoints", Array.from(attr.array), 4);\n                    else if (attr.name === "weights")\n                    {\n                        const arr4 = new Float32Array(attr.array.length / attr.itemSize * 4);\n\n                        for (let k = 0; k < attr.array.length / attr.itemSize; k++)\n                        {\n                            arr4[k * 4] = arr4[k * 4 + 1] = arr4[k * 4 + 2] = arr4[k * 4 + 3] = 0;\n                            for (let j = 0; j < attr.itemSize; j++)\n                                arr4[k * 4 + j] = attr.array[k * attr.itemSize + j];\n                        }\n                        geom.setAttribute("attrWeights", arr4, 4);\n                    }\n                    else op.logWarn("unknown draco attrib", attr);\n                }\n\n                geometry.attributes = null;\n                geom.verticesIndices = geometry.index.array;\n\n                this.setGeom(geom);\n\n                this.mesh = null;\n                gltf.loadingMeshes--;\n                gltf.timing.push(["draco decode", Math.round((performance.now() - gltf.startTime))]);\n\n                if (finished)finished(this);\n            }, (error) => { op.logError(error); });\n        }\n        else\n        {\n            gltf.loadingMeshes--;\n            this.fillGeomAttribs(gltf, this.geom, prim.attributes);\n\n            if (prim.targets)\n            {\n                // console.log("prim.targets", prim.targets.length);\n                for (let j = 0; j < prim.targets.length; j++)\n                {\n                    // var tgeom=new CGL.Geometry("gltf_"+this.name);\n                    let tgeom = this.geom.copy();\n\n                    if (prim.hasOwnProperty("indices")) tgeom.verticesIndices = gltf.accBuffers[prim.indices];\n\n                    this.fillGeomAttribs(gltf, tgeom, prim.targets[j], false);\n\n                    { // calculate normals for final position of morphtarget for later...\n                        for (let i = 0; i < tgeom.vertices.length; i++) tgeom.vertices[i] += this.geom.vertices[i];\n                        tgeom.calculateNormals();\n                        for (let i = 0; i < tgeom.vertices.length; i++) tgeom.vertices[i] -= this.geom.vertices[i];\n                    }\n\n                    this.geom.morphTargets.push(tgeom);\n                }\n            }\n            if (finished)finished(this);\n        }\n    }\n\n    _linearToSrgb(x)\n    {\n        if (x <= 0)\n            return 0;\n        else if (x >= 1)\n            return 1;\n        else if (x < 0.0031308)\n            return x * 12.92;\n        else\n            return x ** (1 / 2.2) * 1.055 - 0.055;\n    }\n\n    calcVertexColors(arr)\n    {\n        let vertexColors = null;\n        if (arr instanceof Float32Array)\n        {\n            let div = false;\n            for (let i = 0; i < arr.length; i++)\n            {\n                if (arr[i] > 1)\n                {\n                    div = true;\n                    continue;\n                }\n            }\n\n            if (div)\n                for (let i = 0; i < arr.length; i++) arr[i] /= 65535;\n\n            vertexColors = arr;\n        }\n\n        else if (arr instanceof Uint16Array)\n        {\n            const fb = new Float32Array(arr.length);\n            for (let i = 0; i < arr.length; i++) fb[i] = arr[i] / 65535;\n\n            vertexColors = fb;\n        }\n        else vertexColors = arr;\n\n        for (let i = 0; i < vertexColors.length; i++)\n        {\n            vertexColors[i] = this._linearToSrgb(vertexColors[i]);\n        }\n\n        return vertexColors;\n    }\n\n    fillGeomAttribs(gltf, tgeom, attribs, setGeom)\n    {\n        if (attribs.hasOwnProperty("POSITION")) tgeom.vertices = gltf.accBuffers[attribs.POSITION];\n        if (attribs.hasOwnProperty("NORMAL")) tgeom.vertexNormals = gltf.accBuffers[attribs.NORMAL];\n        if (attribs.hasOwnProperty("TANGENT")) tgeom.tangents = gltf.accBuffers[attribs.TANGENT];\n\n        if (attribs.hasOwnProperty("COLOR_0")) tgeom.vertexColors = this.calcVertexColors(gltf.accBuffers[attribs.COLOR_0]);\n        if (attribs.hasOwnProperty("COLOR_1")) tgeom.setAttribute("attrVertColor1", this.calcVertexColors(gltf.accBuffers[attribs.COLOR_1]), 4);\n        if (attribs.hasOwnProperty("COLOR_2")) tgeom.setAttribute("attrVertColor2", this.calcVertexColors(gltf.accBuffers[attribs.COLOR_2]), 4);\n        if (attribs.hasOwnProperty("COLOR_3")) tgeom.setAttribute("attrVertColor3", this.calcVertexColors(gltf.accBuffers[attribs.COLOR_3]), 4);\n        if (attribs.hasOwnProperty("COLOR_4")) tgeom.setAttribute("attrVertColor4", this.calcVertexColors(gltf.accBuffers[attribs.COLOR_4]), 4);\n\n        if (attribs.hasOwnProperty("TEXCOORD_0"))tgeom.texCoords = gltf.accBuffers[attribs.TEXCOORD_0];\n        if (attribs.hasOwnProperty("TEXCOORD_1"))tgeom.setAttribute("attrTexCoord1", gltf.accBuffers[attribs.TEXCOORD_1], 2);\n        if (attribs.hasOwnProperty("TEXCOORD_2"))tgeom.setAttribute("attrTexCoord2", gltf.accBuffers[attribs.TEXCOORD_2], 2);\n        if (attribs.hasOwnProperty("TEXCOORD_3"))tgeom.setAttribute("attrTexCoord3", gltf.accBuffers[attribs.TEXCOORD_3], 2);\n        if (attribs.hasOwnProperty("TEXCOORD_4"))tgeom.setAttribute("attrTexCoord4", gltf.accBuffers[attribs.TEXCOORD_4], 2);\n\n        if (attribs.hasOwnProperty("WEIGHTS_0"))\n        {\n            tgeom.setAttribute("attrWeights", gltf.accBuffers[attribs.WEIGHTS_0], 4);\n        }\n        if (attribs.hasOwnProperty("JOINTS_0"))\n        {\n            if (!gltf.accBuffers[attribs.JOINTS_0])console.log("no !gltf.accBuffers[attribs.JOINTS_0]");\n            tgeom.setAttribute("attrJoints", gltf.accBuffers[attribs.JOINTS_0], 4);\n        }\n\n        if (attribs.hasOwnProperty("POSITION")) gltf.accBuffersDelete.push(attribs.POSITION);\n        if (attribs.hasOwnProperty("NORMAL")) gltf.accBuffersDelete.push(attribs.NORMAL);\n        if (attribs.hasOwnProperty("TEXCOORD_0")) gltf.accBuffersDelete.push(attribs.TEXCOORD_0);\n        if (attribs.hasOwnProperty("TANGENT")) gltf.accBuffersDelete.push(attribs.TANGENT);\n        if (attribs.hasOwnProperty("COLOR_0"))gltf.accBuffersDelete.push(attribs.COLOR_0);\n        if (attribs.hasOwnProperty("COLOR_0"))gltf.accBuffersDelete.push(attribs.COLOR_0);\n        if (attribs.hasOwnProperty("COLOR_1"))gltf.accBuffersDelete.push(attribs.COLOR_1);\n        if (attribs.hasOwnProperty("COLOR_2"))gltf.accBuffersDelete.push(attribs.COLOR_2);\n        if (attribs.hasOwnProperty("COLOR_3"))gltf.accBuffersDelete.push(attribs.COLOR_3);\n\n        if (attribs.hasOwnProperty("TEXCOORD_1")) gltf.accBuffersDelete.push(attribs.TEXCOORD_1);\n        if (attribs.hasOwnProperty("TEXCOORD_2")) gltf.accBuffersDelete.push(attribs.TEXCOORD_2);\n        if (attribs.hasOwnProperty("TEXCOORD_3")) gltf.accBuffersDelete.push(attribs.TEXCOORD_3);\n        if (attribs.hasOwnProperty("TEXCOORD_4")) gltf.accBuffersDelete.push(attribs.TEXCOORD_4);\n\n        if (setGeom !== false) if (tgeom && tgeom.verticesIndices) this.setGeom(tgeom);\n    }\n\n    setGeom(geom)\n    {\n        if (inNormFormat.get() == "X-ZY")\n        {\n            for (let i = 0; i < geom.vertexNormals.length; i += 3)\n            {\n                let t = geom.vertexNormals[i + 2];\n                geom.vertexNormals[i + 2] = geom.vertexNormals[i + 1];\n                geom.vertexNormals[i + 1] = -t;\n            }\n        }\n\n        if (inVertFormat.get() == "XZ-Y")\n        {\n            for (let i = 0; i < geom.vertices.length; i += 3)\n            {\n                let t = geom.vertices[i + 2];\n                geom.vertices[i + 2] = -geom.vertices[i + 1];\n                geom.vertices[i + 1] = t;\n            }\n        }\n\n        if (this.primitive == this.TRIANGLES)\n        {\n            if (!geom.vertexNormals.length || inCalcNormals.get()) geom.calculateNormals();\n\n            if ((!geom.biTangents || geom.biTangents.length == 0) && geom.tangents)\n            {\n                const bitan = vec3.create();\n                const tan = vec3.create();\n\n                const tangents = geom.tangents;\n                geom.tangents = new Float32Array(tangents.length / 4 * 3);\n                geom.biTangents = new Float32Array(tangents.length / 4 * 3);\n\n                for (let i = 0; i < tangents.length; i += 4)\n                {\n                    const idx = i / 4 * 3;\n\n                    vec3.cross(\n                        bitan,\n                        [geom.vertexNormals[idx], geom.vertexNormals[idx + 1], geom.vertexNormals[idx + 2]],\n                        [tangents[i], tangents[i + 1], tangents[i + 2]]\n                    );\n\n                    vec3.div(bitan, bitan, [tangents[i + 3], tangents[i + 3], tangents[i + 3]]);\n                    vec3.normalize(bitan, bitan);\n\n                    geom.biTangents[idx + 0] = bitan[0];\n                    geom.biTangents[idx + 1] = bitan[1];\n                    geom.biTangents[idx + 2] = bitan[2];\n\n                    geom.tangents[idx + 0] = tangents[i + 0];\n                    geom.tangents[idx + 1] = tangents[i + 1];\n                    geom.tangents[idx + 2] = tangents[i + 2];\n                }\n            }\n\n            if (geom.tangents.length === 0 || inCalcNormals.get()) geom.calcTangentsBitangents();\n        }\n\n        this.geom = geom;\n\n        this.bounds = geom.getBounds();\n    }\n\n    render(cgl, ignoreMaterial, skinRenderer)\n    {\n        if (!this.mesh && this.geom && this.geom.verticesIndices)\n        {\n            let g = this.geom;\n            if (this.geom.vertices.length / 3 > 64000)\n            {\n                g = this.geom.copy();\n                g.unIndex(false, true);\n            }\n\n            let glprim;\n            if (this.primitive == this.TRIANGLES)glprim = cgl.gl.TRIANGLES;\n            else if (this.primitive == this.LINES)glprim = cgl.gl.LINES;\n            else if (this.primitive == this.LINE_STRIP)glprim = cgl.gl.LINE_STRIP;\n            else if (this.primitive == this.POINTS)glprim = cgl.gl.POINTS;\n            else\n            {\n                op.logWarn("unknown primitive type", this);\n            }\n\n            this.mesh = new CGL.Mesh(cgl, g, glprim);\n            // this.mesh._geom = null;\n        }\n        else\n        {\n            // update morphTargets\n            if (this.geom && this.geom.morphTargets.length)\n            {\n                this.morphGeom = this.geom.copy();\n\n                this.test = time * 11.7;\n\n                if (this.test >= this.geom.morphTargets.length - 1) this.test = 0;\n\n                const mt = this.geom.morphTargets[Math.floor(this.test)];\n                const mt2 = this.geom.morphTargets[Math.floor(this.test + 1)];\n\n                if (mt && mt.vertices && mt2)\n                {\n                    if (this.morphGeom.vertexNormals.length != mt.vertexNormals.length)\n                        this.morphGeom.vertexNormals = new Float32Array(mt.vertexNormals.length);\n\n                    const fract = this.test % 1;\n                    for (let i = 0; i < this.morphGeom.vertices.length; i++)\n                    {\n                        this.morphGeom.vertices[i] =\n                            this.geom.vertices[i] +\n                            (1.0 - fract) * mt.vertices[i] +\n                            fract * mt2.vertices[i];\n\n                        this.morphGeom.vertexNormals[i] =\n                            (1.0 - fract) * mt.vertexNormals[i] +\n                            fract * mt2.vertexNormals[i];\n                    }\n\n                    this.mesh.updateNormals(this.morphGeom);\n                    this.mesh.updateVertices(this.morphGeom);\n                }\n            }\n\n            let useMat = !ignoreMaterial && this.material != -1 && gltf.shaders[this.material];\n            if (skinRenderer)useMat = false;\n\n            if (useMat) cgl.pushShader(gltf.shaders[this.material]);\n\n            const currentShader = cgl.getShader() || {};\n            const uniDiff = currentShader.uniformColorDiffuse;\n\n            const uniPbrMetalness = currentShader.uniformPbrMetalness;\n            const uniPbrRoughness = currentShader.uniformPbrRoughness;\n\n            if (!gltf.shaders[this.material] && inUseMatProps.get())\n            {\n                if (uniDiff && this._matDiffuseColor)\n                {\n                    this._matDiffuseColorOrig = [uniDiff.getValue()[0], uniDiff.getValue()[1], uniDiff.getValue()[2], uniDiff.getValue()[3]];\n                    uniDiff.setValue(this._matDiffuseColor);\n                }\n\n                if (uniPbrMetalness)\n                    if (this._matPbrMetalness != null)\n                    {\n                        this._matPbrMetalnessOrig = uniPbrMetalness.getValue();\n                        uniPbrMetalness.setValue(this._matPbrMetalness);\n                    }\n                    else\n                        uniPbrMetalness.setValue(0);\n\n                if (uniPbrRoughness)\n                    if (this._matPbrRoughness != null)\n                    {\n                        this._matPbrRoughnessOrig = uniPbrRoughness.getValue();\n                        uniPbrRoughness.setValue(this._matPbrRoughness);\n                    }\n                    else\n                    {\n                        uniPbrRoughness.setValue(0);\n                    }\n            }\n\n            if (this.mesh) this.mesh.render(cgl.getShader(), ignoreMaterial);\n\n            if (inUseMatProps.get())\n            {\n                if (uniDiff && this._matDiffuseColor) uniDiff.setValue(this._matDiffuseColorOrig);\n                if (uniPbrMetalness && this._matPbrMetalnessOrig != undefined) uniPbrMetalness.setValue(this._matPbrMetalnessOrig);\n                if (uniPbrRoughness && this._matPbrRoughnessOrig != undefined) uniPbrRoughness.setValue(this._matPbrRoughnessOrig);\n            }\n\n            if (useMat) cgl.popShader();\n        }\n    }\n};\n',inc_meshGroup_js:"const gltfMeshGroup = class\n{\n    constructor(gltf, m)\n    {\n        this.bounds = new CABLES.CG.BoundingBox();\n        this.meshes = [];\n        this.name = m.name;\n        const prims = m.primitives;\n\n        for (let i = 0; i < prims.length; i++)\n        {\n            const mesh = new gltfMesh(this.name, prims[i], gltf,\n                (mesh) =>\n                {\n                    this.bounds.apply(mesh.bounds);\n                });\n\n            mesh.submeshIndex = i;\n            this.meshes.push(mesh);\n        }\n    }\n\n    render(cgl, ignoreMat, skinRenderer, _time)\n    {\n        for (let i = 0; i < this.meshes.length; i++)\n        {\n            const useMat = gltf.shaders[this.meshes[i].material];\n\n            if (!ignoreMat && useMat) cgl.pushShader(gltf.shaders[this.meshes[i].material]);\n            // console.log(gltf.shaders[this.meshes[i].material],this.meshes[i].material)\n            if (skinRenderer)skinRenderer.renderStart(cgl, _time);\n\n            this.meshes[i].render(cgl, ignoreMat, skinRenderer, _time);\n            if (skinRenderer)skinRenderer.renderFinish(cgl);\n            if (!ignoreMat && useMat) cgl.popShader();\n        }\n    }\n};\n",inc_node_js:'const gltfNode = class\n{\n    constructor(node, gltf)\n    {\n        this.isChild = node.isChild || false;\n        this.name = node.name;\n        if (node.hasOwnProperty("camera")) this.camera = node.camera;\n        this.hidden = false;\n        this.mat = mat4.create();\n        this._animMat = mat4.create();\n        this._tempMat = mat4.create();\n        this._tempQuat = quat.create();\n        this._tempRotmat = mat4.create();\n        this.mesh = null;\n        this.children = [];\n        this._node = node;\n        this._gltf = gltf;\n        this.absMat = mat4.create();\n        this.addTranslate = null;\n        this._tempAnimScale = null;\n        this.addMulMat = null;\n        this.updateMatrix();\n        this._animActions = {};\n        this.skinRenderer = null;\n        this.copies = [];\n    }\n\n    get skin()\n    {\n        if (this._node.hasOwnProperty("skin")) return this._node.skin;\n        else return -1;\n    }\n\n    copy()\n    {\n        this.isCopy = true;\n        const n = new gltfNode(this._node, this._gltf);\n        n.copyOf = this;\n\n        n._animActions = this._animActions;\n        n.children = this.children;\n        n.skinRenderer = new GltfSkin(n);\n\n        this.updateMatrix();\n        return n;\n    }\n\n    hasSkin()\n    {\n        if (this._node.hasOwnProperty("skin")) return this._gltf.json.skins[this._node.skin].name || "unknown";\n        return false;\n    }\n\n    initSkin()\n    {\n        if (this.skin > -1)\n        {\n            this.skinRenderer = new GltfSkin(this);\n        }\n    }\n\n    updateMatrix()\n    {\n        mat4.identity(this.mat);\n        if (this._node.translation) mat4.translate(this.mat, this.mat, this._node.translation);\n\n        if (this._node.rotation)\n        {\n            const rotmat = mat4.create();\n            this._rot = this._node.rotation;\n\n            mat4.fromQuat(rotmat, this._node.rotation);\n            mat4.mul(this.mat, this.mat, rotmat);\n        }\n\n        if (this._node.scale)\n        {\n            this._scale = this._node.scale;\n            mat4.scale(this.mat, this.mat, this._scale);\n        }\n\n        if (this._node.hasOwnProperty("mesh"))\n        {\n            this.mesh = this._gltf.meshes[this._node.mesh];\n            if (this.isCopy)\n            {\n                console.log(this.mesh);\n            }\n        }\n\n        if (this._node.children)\n        {\n            for (let i = 0; i < this._node.children.length; i++)\n            {\n                this._gltf.json.nodes[i].isChild = true;\n                if (this._gltf.nodes[this._node.children[i]]) this._gltf.nodes[this._node.children[i]].isChild = true;\n                this.children.push(this._node.children[i]);\n            }\n        }\n    }\n\n    unHide()\n    {\n        this.hidden = false;\n        for (let i = 0; i < this.children.length; i++)\n            if (this.children[i].unHide) this.children[i].unHide();\n    }\n\n    calcBounds(gltf, mat, bounds)\n    {\n        const localMat = mat4.create();\n\n        if (mat) mat4.copy(localMat, mat);\n        if (this.mat) mat4.mul(localMat, localMat, this.mat);\n\n        if (this.mesh)\n        {\n            const bb = this.mesh.bounds.copy();\n            bb.mulMat4(localMat);\n            bounds.apply(bb);\n\n            if (bounds.changed)\n            {\n                boundingPoints.push(\n                    bb._min[0] || 0, bb._min[1] || 0, bb._min[2] || 0,\n                    bb._max[0] || 0, bb._max[1] || 0, bb._max[2] || 0);\n            }\n        }\n\n        for (let i = 0; i < this.children.length; i++)\n        {\n            if (gltf.nodes[this.children[i]] && gltf.nodes[this.children[i]].calcBounds)\n            {\n                const b = gltf.nodes[this.children[i]].calcBounds(gltf, localMat, bounds);\n\n                bounds.apply(b);\n            }\n        }\n\n        if (bounds.changed) return bounds;\n        else return null;\n    }\n\n    setAnimAction(name)\n    {\n        // console.log("setAnimAction:", name);\n        if (!name) return;\n\n        this._currentAnimaction = name;\n\n        if (name && !this._animActions[name])\n        {\n            // console.log("no action found:", name,this._animActions);\n            return null;\n        }\n\n        // else console.log("YES action found:", name);\n        // console.log(this._animActions);\n\n        for (let path in this._animActions[name])\n        {\n            if (path == "translation") this._animTrans = this._animActions[name][path];\n            else if (path == "rotation") this._animRot = this._animActions[name][path];\n            else if (path == "scale") this._animScale = this._animActions[name][path];\n            else console.warn("unknown anim path", path, this._animActions[name][path]);\n        }\n    }\n\n    setAnim(path, name, anims)\n    {\n        if (!path || !name || !anims) return;\n\n        // console.log("setanim", this._node.name, path, name, anims);\n\n        this._animActions[name] = this._animActions[name] || {};\n\n        // console.log(this._animActions);\n        // debugger;\n\n        // for (let i = 0; i < this.copies.length; i++) this.copies[i]._animActions = this._animActions;\n\n        if (this._animActions[name][path]) op.warn("animation action path already exists", name, path, this._animActions[name][path]);\n\n        this._animActions[name][path] = anims;\n\n        if (path == "translation") this._animTrans = anims;\n        else if (path == "rotation") this._animRot = anims;\n        else if (path == "scale") this._animScale = anims;\n        else console.warn("unknown anim path", path, anims);\n    }\n\n    modelMatLocal()\n    {\n        return this._animMat || this.mat;\n    }\n\n    modelMatAbs()\n    {\n        return this.absMat;\n    }\n\n    transform(cgl, _time)\n    {\n        if (!_time && _time != 0)_time = time;\n\n        this._lastTimeTrans = _time;\n\n        // console.log(this._rot)\n\n        gltfTransforms++;\n\n        if (!this._animTrans && !this._animRot && !this._animScale)\n        {\n            mat4.mul(cgl.mMatrix, cgl.mMatrix, this.mat);\n            this._animMat = null;\n        }\n        else\n        {\n            this._animMat = this._animMat || mat4.create();\n            mat4.identity(this._animMat);\n\n            const playAnims = true;\n\n            if (playAnims && this._animTrans)\n            {\n                mat4.translate(this._animMat, this._animMat, [\n                    this._animTrans[0].getValue(_time),\n                    this._animTrans[1].getValue(_time),\n                    this._animTrans[2].getValue(_time)]);\n            }\n            else\n            if (this._node.translation) mat4.translate(this._animMat, this._animMat, this._node.translation);\n\n            if (playAnims && this._animRot)\n            {\n                if (this._animRot[0].defaultEasing == CABLES.EASING_LINEAR) CABLES.Anim.slerpQuaternion(_time, this._tempQuat, this._animRot[0], this._animRot[1], this._animRot[2], this._animRot[3]);\n                else if (this._animRot[0].defaultEasing == CABLES.EASING_ABSOLUTE)\n                {\n                    this._tempQuat[0] = this._animRot[0].getValue(_time);\n                    this._tempQuat[1] = this._animRot[1].getValue(_time);\n                    this._tempQuat[2] = this._animRot[2].getValue(_time);\n                    this._tempQuat[3] = this._animRot[3].getValue(_time);\n                }\n                else if (this._animRot[0].defaultEasing == CABLES.EASING_CUBICSPLINE)\n                {\n                    CABLES.Anim.slerpQuaternion(_time, this._tempQuat, this._animRot[0], this._animRot[1], this._animRot[2], this._animRot[3]);\n                }\n\n                mat4.fromQuat(this._tempMat, this._tempQuat);\n                mat4.mul(this._animMat, this._animMat, this._tempMat);\n            }\n            else if (this._rot)\n            {\n                // mat4.fromQuat(this._tempRotmat, this._rot);\n                // mat4.mul(this._animMat, this._animMat, this._tempRotmat);\n            }\n\n            if (playAnims && this._animScale)\n            {\n                if (!this._tempAnimScale) this._tempAnimScale = [1, 1, 1];\n                this._tempAnimScale[0] = this._animScale[0].getValue(_time);\n                this._tempAnimScale[1] = this._animScale[1].getValue(_time);\n                this._tempAnimScale[2] = this._animScale[2].getValue(_time);\n                mat4.scale(this._animMat, this._animMat, this._tempAnimScale);\n            }\n            else if (this._scale) mat4.scale(this._animMat, this._animMat, this._scale);\n\n            mat4.mul(cgl.mMatrix, cgl.mMatrix, this._animMat);\n        }\n\n        if (this.addTranslate) mat4.translate(cgl.mMatrix, cgl.mMatrix, this.addTranslate);\n\n        if (this.addMulMat) mat4.mul(cgl.mMatrix, cgl.mMatrix, this.addMulMat);\n\n        mat4.copy(this.absMat, cgl.mMatrix);\n    }\n\n    render(cgl, dontTransform, dontDrawMesh, ignoreMaterial, ignoreChilds, drawHidden, _time)\n    {\n        if (!dontTransform) cgl.pushModelMatrix();\n\n        if (_time === undefined) _time = gltf.time;\n\n        if (!dontTransform || this.skinRenderer) this.transform(cgl, _time);\n\n        if (this.hidden && !drawHidden)\n        {\n        }\n        else\n        {\n            if (this.skinRenderer)\n            {\n                this.skinRenderer.time = _time;\n                if (!dontDrawMesh)\n                    this.mesh.render(cgl, ignoreMaterial, this.skinRenderer, _time);\n            }\n            else\n            {\n                if (this.mesh && !dontDrawMesh)\n                    this.mesh.render(cgl, ignoreMaterial, null, _time);\n            }\n        }\n\n        if (!ignoreChilds && !this.hidden)\n            for (let i = 0; i < this.children.length; i++)\n                if (gltf.nodes[this.children[i]])\n                    gltf.nodes[this.children[i]].render(cgl, dontTransform, dontDrawMesh, ignoreMaterial, ignoreChilds, drawHidden, _time);\n\n        if (!dontTransform)cgl.popModelMatrix();\n    }\n};\n',inc_print_js:'let tab = null;\n\nfunction closeTab()\n{\n    if (tab)gui.mainTabs.closeTab(tab.id);\n    tab = null;\n}\n\nfunction formatVec(arr)\n{\n    const nums = [];\n    for (let i = 0; i < arr.length; i++)\n    {\n        nums.push(Math.round(arr[i] * 1000) / 1000);\n    }\n\n    return nums.join(",");\n}\n\nfunction printNode(html, node, level)\n{\n    if (!gltf) return;\n\n    html += "<tr class=\\"row\\">";\n\n    let ident = "";\n    let identSpace = "";\n\n    for (let i = 1; i < level; i++)\n    {\n        identSpace += "&nbsp;&nbsp;&nbsp;";\n        let identClass = "identBg";\n        if (i == 1)identClass = "identBgLevel0";\n        ident += "<td class=\\"ident " + identClass + "\\" ><div style=\\"\\"></div></td>";\n    }\n    let id = CABLES.uuid();\n    html += ident;\n    html += "<td colspan=\\"" + (21 - level) + "\\">";\n\n    if (node.mesh && node.mesh.meshes.length)html += "<span class=\\"icon icon-cube\\"></span>&nbsp;";\n    else html += "<span class=\\"icon icon-box-select\\"></span> &nbsp;";\n\n    html += node.name + "</td><td></td>";\n\n    if (node.mesh)\n    {\n        html += "<td>";\n        for (let i = 0; i < node.mesh.meshes.length; i++)\n        {\n            if (i > 0)html += ", ";\n            html += node.mesh.meshes[i].name;\n        }\n\n        html += "</td>";\n\n        html += "<td>";\n        html += node.hasSkin() || "-";\n        html += "</td>";\n\n        html += "<td>";\n        let countMats = 0;\n        for (let i = 0; i < node.mesh.meshes.length; i++)\n        {\n            if (countMats > 0)html += ", ";\n            if (gltf.json.materials && node.mesh.meshes[i].hasOwnProperty("material"))\n            {\n                if (gltf.json.materials[node.mesh.meshes[i].material])\n                {\n                    html += gltf.json.materials[node.mesh.meshes[i].material].name;\n                    countMats++;\n                }\n            }\n        }\n        if (countMats == 0)html += "none";\n        html += "</td>";\n    }\n    else\n    {\n        html += "<td>-</td><td>-</td><td>-</td>";\n    }\n\n    html += "<td>";\n\n    if (node._node.translation || node._node.rotation || node._node.scale)\n    {\n        let info = "";\n\n        if (node._node.translation)info += "Translate: `" + formatVec(node._node.translation) + "` || ";\n        if (node._node.rotation)info += "Rotation: `" + formatVec(node._node.rotation) + "` || ";\n        if (node._node.scale)info += "Scale: `" + formatVec(node._node.scale) + "` || ";\n\n        html += "<span class=\\"icon icon-gizmo info\\" data-info=\\"" + info + "\\"></span> &nbsp;";\n    }\n\n    if (node._animRot || node._animScale || node._animTrans)\n    {\n        let info = "Animated: ";\n        if (node._animRot) info += "Rot ";\n        if (node._animScale) info += "Scale ";\n        if (node._animTrans) info += "Trans ";\n\n        html += "<span class=\\"icon icon-clock info\\" data-info=\\"" + info + "\\"></span>&nbsp;";\n    }\n\n    if (!node._node.translation && !node._node.rotation && !node._node.scale && !node._animRot && !node._animScale && !node._animTrans) html += "-";\n\n    html += "</td>";\n\n    html += "<td>";\n    let hideclass = "";\n    if (node.hidden)hideclass = "node-hidden";\n\n    // html+=\'\';\n    html += "<a onclick=\\"gui.corePatch().getOpById(\'" + op.id + "\').exposeNode(\'" + node.name + "\',\'transform\')\\" class=\\"treebutton\\">Transform</a>";\n    html += " <a onclick=\\"gui.corePatch().getOpById(\'" + op.id + "\').exposeNode(\'" + node.name + "\',\'hierarchy\')\\" class=\\"treebutton\\">Hierarchy</a>";\n    html += " <a onclick=\\"gui.corePatch().getOpById(\'" + op.id + "\').exposeNode(\'" + node.name + "\')\\" class=\\"treebutton\\">Node</a>";\n\n    if (node.hasSkin())\n        html += " <a onclick=\\"gui.corePatch().getOpById(\'" + op.id + "\').exposeNode(\'" + node.name + "\',false,{skin:true});\\" class=\\"treebutton\\">Skin</a>";\n\n    html += "</td><td>";\n    html += "&nbsp;<span class=\\"icon iconhover icon-eye " + hideclass + "\\" onclick=\\"gui.corePatch().getOpById(\'" + op.id + "\').toggleNodeVisibility(\'" + node.name + "\');this.classList.toggle(\'node-hidden\');\\"></span>";\n    html += "</td>";\n\n    html += "</tr>";\n\n    if (node.children)\n    {\n        for (let i = 0; i < node.children.length; i++)\n            html = printNode(html, gltf.nodes[node.children[i]], level + 1);\n    }\n\n    return html;\n}\n\nfunction printMaterial(mat, idx)\n{\n    let html = "<tr>";\n    html += " <td>" + idx + "</td>";\n    html += " <td>" + mat.name + "</td>";\n    // html+=\' <td><a onclick="" class="treebutton">Assign</a><td>\';\n\n    html += " <td>";\n\n    const info = JSON.stringify(mat, null, 4).replaceAll("\\"", "").replaceAll("\\n", "<br/>");\n\n    html += "<span class=\\"icon icon-info\\" onclick=\\"new CABLES.UI.ModalDialog({ \'html\': \'<pre>" + info + "</pre>\', \'title\': \'" + mat.name + "\' });\\"></span>&nbsp;";\n\n    if (mat.pbrMetallicRoughness && mat.pbrMetallicRoughness.baseColorFactor)\n    {\n        let rgb = "";\n        rgb += "" + Math.round(mat.pbrMetallicRoughness.baseColorFactor[0] * 255);\n        rgb += "," + Math.round(mat.pbrMetallicRoughness.baseColorFactor[1] * 255);\n        rgb += "," + Math.round(mat.pbrMetallicRoughness.baseColorFactor[2] * 255);\n\n        html += "<div style=\\"width:15px;height:15px;background-color:rgb(" + rgb + ");display:inline-block\\">&nbsp;</a>";\n    }\n    html += " <td style=\\"\\">" + (gltf.shaders[idx] ? "-" : "<a onclick=\\"gui.corePatch().getOpById(\'" + op.id + "\').assignMaterial(\'" + mat.name + "\')\\" class=\\"treebutton\\">Assign</a>") + "<td>";\n    html += "<td>";\n\n    html += "</tr>";\n    return html;\n}\n\nfunction printInfo()\n{\n    if (!gltf) return;\n\n    const startTime = performance.now();\n    const sizes = {};\n    let html = "<div style=\\"overflow:scroll;width:100%;height:100%\\">";\n\n    html += "File: <a href=\\"" + CABLES.platform.getCablesUrl() + "/asset/patches/?filename=" + inFile.get() + "\\" target=\\"_blank\\">" + CABLES.basename(inFile.get()) + "</a><br/>";\n\n    html += "Generator:" + gltf.json.asset.generator;\n\n    let numNodes = 0;\n    if (gltf.json.nodes)numNodes = gltf.json.nodes.length;\n    html += "<div id=\\"groupNodes\\">Nodes (" + numNodes + ")</div>";\n\n    html += "<table id=\\"sectionNodes\\" class=\\"table treetable\\">";\n\n    html += "<tr>";\n    html += " <th colspan=\\"21\\">Name</th>";\n    html += " <th>Mesh</th>";\n    html += " <th>Skin</th>";\n    html += " <th>Material</th>";\n    html += " <th>Transform</th>";\n    html += " <th>Expose</th>";\n    html += " <th></th>";\n    html += "</tr>";\n\n    for (let i = 0; i < gltf.nodes.length; i++)\n    {\n        if (!gltf.nodes[i].isChild)\n            html = printNode(html, gltf.nodes[i], 1);\n    }\n    html += "</table>";\n\n    // / //////////////////\n\n    let numMaterials = 0;\n    if (gltf.json.materials)numMaterials = gltf.json.materials.length;\n    html += "<div id=\\"groupMaterials\\">Materials (" + numMaterials + ")</div>";\n\n    if (!gltf.json.materials || gltf.json.materials.length == 0)\n    {\n    }\n    else\n    {\n        html += "<table id=\\"materialtable\\"  class=\\"table treetable\\">";\n        html += "<tr>";\n        html += " <th>Index</th>";\n        html += " <th>Name</th>";\n        html += " <th>Color</th>";\n        html += " <th>Function</th>";\n        html += " <th></th>";\n        html += "</tr>";\n        for (let i = 0; i < gltf.json.materials.length; i++)\n        {\n            html += printMaterial(gltf.json.materials[i], i);\n        }\n        html += "</table>";\n    }\n\n    // / ///////////////////////\n\n    html += "<div id=\\"groupMeshes\\">Meshes (" + gltf.json.meshes.length + ")</div>";\n\n    html += "<table id=\\"meshestable\\"  class=\\"table treetable\\">";\n    html += "<tr>";\n    html += " <th>Name</th>";\n    html += " <th>Node</th>";\n    html += " <th>Material</th>";\n    html += " <th>Vertices</th>";\n    html += " <th>Attributes</th>";\n    html += "</tr>";\n\n    let sizeBufferViews = [];\n    sizes.meshes = 0;\n\n    for (let i = 0; i < gltf.json.meshes.length; i++)\n    {\n        html += "<tr>";\n        html += "<td>" + gltf.json.meshes[i].name + "</td>";\n\n        html += "<td>";\n        let count = 0;\n        let nodename = "";\n        for (var j = 0; j < gltf.json.nodes.length; j++)\n        {\n            if (gltf.json.nodes[j].mesh == i)\n            {\n                count++;\n                if (count == 1)\n                {\n                    nodename = gltf.json.nodes[j].name;\n                }\n            }\n        }\n        if (count > 1) html += (count) + " nodes (" + nodename + " ...)";\n        else html += nodename;\n        html += "</td>";\n\n        // -------\n\n        html += "<td>";\n        for (var j = 0; j < gltf.json.meshes[i].primitives.length; j++)\n        {\n            if (gltf.json.meshes[i].primitives[j].hasOwnProperty("material"))\n            {\n                if (gltf.json.materials[gltf.json.meshes[i]])\n                {\n                    html += gltf.json.materials[gltf.json.meshes[i].primitives[j].material].name + " ";\n                }\n            }\n            else html += "None";\n        }\n        html += "</td>";\n\n        html += "<td>";\n        let numVerts = 0;\n        for (var j = 0; j < gltf.json.meshes[i].primitives.length; j++)\n        {\n            if (gltf.json.meshes[i].primitives[j].attributes.POSITION != undefined)\n            {\n                let v = parseInt(gltf.json.accessors[gltf.json.meshes[i].primitives[j].attributes.POSITION].count);\n                numVerts += v;\n                html += "" + v + "<br/>";\n            }\n            else html += "-<br/>";\n        }\n\n        if (gltf.json.meshes[i].primitives.length > 0)\n            html += "=" + numVerts;\n        html += "</td>";\n\n        html += "<td style=\\"vertical-align:top;\\">";\n        for (let j = 0; j < gltf.json.meshes[i].primitives.length; j++)\n        {\n            html += Object.keys(gltf.json.meshes[i].primitives[j].attributes);\n            html += " <a onclick=\\"gui.corePatch().getOpById(\'" + op.id + "\').exposeGeom(\'" + gltf.json.meshes[i].name + "\'," + j + ")\\" class=\\"treebutton\\">Geometry</a>";\n            html += "<br/>";\n        }\n        html += "</td>";\n        html += "</tr>";\n\n        for (let j = 0; j < gltf.json.meshes[i].primitives.length; j++)\n        {\n            const accessor = gltf.json.accessors[gltf.json.meshes[i].primitives[j].indices];\n            if (accessor)\n            {\n                let bufView = accessor.bufferView;\n\n                if (sizeBufferViews.indexOf(bufView) == -1)\n                {\n                    sizeBufferViews.push(bufView);\n                    if (gltf.json.bufferViews[bufView])sizes.meshes += gltf.json.bufferViews[bufView].byteLength;\n                }\n            }\n\n            for (let k in gltf.json.meshes[i].primitives[j].attributes)\n            {\n                const attr = gltf.json.meshes[i].primitives[j].attributes[k];\n                const bufView2 = gltf.json.accessors[attr].bufferView;\n\n                if (sizeBufferViews.indexOf(bufView2) == -1)\n                {\n                    sizeBufferViews.push(bufView2);\n                    if (gltf.json.bufferViews[bufView2])sizes.meshes += gltf.json.bufferViews[bufView2].byteLength;\n                }\n            }\n        }\n    }\n    html += "</table>";\n\n    // / //////////////////////////////////\n\n    let numSamplers = 0;\n    let numAnims = 0;\n\n    if (gltf.json.animations)\n    {\n        numAnims = gltf.json.animations.length;\n        for (let i = 0; i < gltf.json.animations.length; i++)\n            numSamplers += gltf.json.animations[i].samplers.length;\n    }\n\n    html += "<div id=\\"groupAnims\\">Animations (" + numAnims + "/" + numSamplers + ")</div>";\n\n    if (gltf.json.animations)\n    {\n        html += "<table id=\\"sectionAnim\\" class=\\"table treetable\\">";\n        html += "<tr>";\n        html += "  <th>Name</th>";\n        html += "  <th>Target node</th>";\n        html += "  <th>Path</th>";\n        html += "  <th>Interpolation</th>";\n        html += "  <th>Keys</th>";\n        html += "</tr>";\n\n        sizes.animations = 0;\n\n        for (let i = 0; i < gltf.json.animations.length; i++)\n        {\n            for (let j = 0; j < gltf.json.animations[i].samplers.length; j++)\n            {\n                let bufView = gltf.json.accessors[gltf.json.animations[i].samplers[j].input].bufferView;\n                if (sizeBufferViews.indexOf(bufView) == -1)\n                {\n                    sizeBufferViews.push(bufView);\n                    sizes.animations += gltf.json.bufferViews[bufView].byteLength;\n                }\n\n                bufView = gltf.json.accessors[gltf.json.animations[i].samplers[j].output].bufferView;\n                if (sizeBufferViews.indexOf(bufView) == -1)\n                {\n                    sizeBufferViews.push(bufView);\n                    sizes.animations += gltf.json.bufferViews[bufView].byteLength;\n                }\n            }\n\n            for (let j = 0; j < gltf.json.animations[i].channels.length; j++)\n            {\n                html += "<tr>";\n                html += "  <td> Anim " + i + ": " + gltf.json.animations[i].name + "</td>";\n\n                html += "  <td>" + gltf.nodes[gltf.json.animations[i].channels[j].target.node].name + "</td>";\n                html += "  <td>";\n                html += gltf.json.animations[i].channels[j].target.path + " ";\n                html += "  </td>";\n\n                const smplidx = gltf.json.animations[i].channels[j].sampler;\n                const smplr = gltf.json.animations[i].samplers[smplidx];\n\n                html += "  <td>" + smplr.interpolation + "</td>";\n\n                html += "  <td>" + gltf.json.accessors[smplr.output].count;\n\n                // html += "&nbsp;&nbsp;<a onclick=\\"gui.corePatch().getOpById(\'" + op.id + "\').showAnim(\'" + i + "\',\'" + j + "\')\\" class=\\"icon icon-search\\"></a>";\n\n                html += "</td>";\n\n                html += "</tr>";\n            }\n        }\n        html += "</table>";\n    }\n    else\n    {\n\n    }\n\n    // / ///////////////////\n\n    let numImages = 0;\n    if (gltf.json.images)numImages = gltf.json.images.length;\n    html += "<div id=\\"groupImages\\">Images (" + numImages + ")</div>";\n\n    if (gltf.json.images)\n    {\n        html += "<table id=\\"sectionImages\\" class=\\"table treetable\\">";\n\n        html += "<tr>";\n        html += "  <th>name</th>";\n        html += "  <th>type</th>";\n        html += "  <th>func</th>";\n\n        html += "</tr>";\n\n        sizes.images = 0;\n\n        for (let i = 0; i < gltf.json.images.length; i++)\n        {\n            if (gltf.json.images[i].bufferView)\n                sizes.images += gltf.json.bufferViews[gltf.json.images[i].bufferView].byteLength;\n\n            html += "<tr>";\n            html += "<td>" + gltf.json.images[i].name + "</td>";\n            html += "<td>" + gltf.json.images[i].mimeType + "</td>";\n            html += "<td>";\n\n            let name = gltf.json.images[i].name;\n            if (name === undefined)name = gltf.json.images[i].bufferView;\n\n            html += "<a onclick=\\"gui.corePatch().getOpById(\'" + op.id + "\').exposeTexture(\'" + name + "\')\\" class=\\"treebutton\\">Expose</a>";\n            html += "</td>";\n\n            html += "<tr>";\n        }\n        html += "</table>";\n    }\n\n    // / ///////////////////////\n\n    let numCameras = 0;\n    if (gltf.json.cameras)numCameras = gltf.json.cameras.length;\n    html += "<div id=\\"groupCameras\\">Cameras (" + numCameras + ")</div>";\n\n    if (gltf.json.cameras)\n    {\n        html += "<table id=\\"sectionCameras\\" class=\\"table treetable\\">";\n\n        html += "<tr>";\n        html += "  <th>name</th>";\n        html += "  <th>type</th>";\n        html += "  <th>info</th>";\n        html += "</tr>";\n\n        for (let i = 0; i < gltf.json.cameras.length; i++)\n        {\n            html += "<tr>";\n            html += "<td>" + gltf.json.cameras[i].name + "</td>";\n            html += "<td>" + gltf.json.cameras[i].type + "</td>";\n            html += "<td>";\n\n            if (gltf.json.cameras[i].perspective)\n            {\n                html += "yfov: " + Math.round(gltf.json.cameras[i].perspective.yfov * 100) / 100;\n                html += ", ";\n                html += "zfar: " + Math.round(gltf.json.cameras[i].perspective.zfar * 100) / 100;\n                html += ", ";\n                html += "znear: " + Math.round(gltf.json.cameras[i].perspective.znear * 100) / 100;\n            }\n            html += "</td>";\n\n            html += "<tr>";\n        }\n        html += "</table>";\n    }\n\n    // / ////////////////////////////////////\n\n    let numSkins = 0;\n    if (gltf.json.skins)numSkins = gltf.json.skins.length;\n    html += "<div id=\\"groupSkins\\">Skins (" + numSkins + ")</div>";\n\n    if (gltf.json.skins)\n    {\n        // html += "<h3>Skins (" + gltf.json.skins.length + ")</h3>";\n        html += "<table id=\\"sectionSkins\\" class=\\"table treetable\\">";\n\n        html += "<tr>";\n        html += "  <th>name</th>";\n        html += "  <th></th>";\n        html += "  <th>total joints</th>";\n        html += "</tr>";\n\n        for (let i = 0; i < gltf.json.skins.length; i++)\n        {\n            html += "<tr>";\n            html += "<td>" + gltf.json.skins[i].name + "</td>";\n            html += "<td>" + "</td>";\n            html += "<td>" + gltf.json.skins[i].joints.length + "</td>";\n            html += "<td>";\n            html += "</td>";\n            html += "<tr>";\n        }\n        html += "</table>";\n    }\n\n    // / ////////////////////////////////////\n\n    if (gltf.timing)\n    {\n        html += "<div id=\\"groupTiming\\">Debug Loading Timing </div>";\n\n        html += "<table id=\\"sectionTiming\\" class=\\"table treetable\\">";\n\n        html += "<tr>";\n        html += "  <th>task</th>";\n        html += "  <th>time used</th>";\n        html += "</tr>";\n\n        let lt = 0;\n        for (let i = 0; i < gltf.timing.length - 1; i++)\n        {\n            html += "<tr>";\n            html += "  <td>" + gltf.timing[i][0] + "</td>";\n            html += "  <td>" + (gltf.timing[i + 1][1] - gltf.timing[i][1]) + " ms</td>";\n            html += "</tr>";\n            // lt = gltf.timing[i][1];\n        }\n        html += "</table>";\n    }\n\n    // / //////////////////////////\n\n    let sizeBin = 0;\n    if (gltf.json.buffers)\n        sizeBin = gltf.json.buffers[0].byteLength;\n\n    html += "<div id=\\"groupBinary\\">File Size Allocation (" + Math.round(sizeBin / 1024) + "k )</div>";\n\n    html += "<table id=\\"sectionBinary\\" class=\\"table treetable\\">";\n    html += "<tr>";\n    html += "  <th>name</th>";\n    html += "  <th>size</th>";\n    html += "  <th>%</th>";\n    html += "</tr>";\n    let sizeUnknown = sizeBin;\n    for (let i in sizes)\n    {\n        // html+=i+\':\'+Math.round(sizes[i]/1024);\n        html += "<tr>";\n        html += "<td>" + i + "</td>";\n        html += "<td>" + readableSize(sizes[i]) + " </td>";\n        html += "<td>" + Math.round(sizes[i] / sizeBin * 100) + "% </td>";\n        html += "<tr>";\n        sizeUnknown -= sizes[i];\n    }\n\n    if (sizeUnknown != 0)\n    {\n        html += "<tr>";\n        html += "<td>unknown</td>";\n        html += "<td>" + readableSize(sizeUnknown) + " </td>";\n        html += "<td>" + Math.round(sizeUnknown / sizeBin * 100) + "% </td>";\n        html += "<tr>";\n    }\n\n    html += "</table>";\n    html += "</div>";\n\n    tab = new CABLES.UI.Tab("GLTF " + CABLES.basename(inFile.get()), { "icon": "cube", "infotext": "tab_gltf", "padding": true, "singleton": true });\n    gui.mainTabs.addTab(tab, true);\n\n    tab.addEventListener("close", closeTab);\n    tab.html(html);\n\n    CABLES.UI.Collapsable.setup(ele.byId("groupNodes"), ele.byId("sectionNodes"), false);\n    CABLES.UI.Collapsable.setup(ele.byId("groupMaterials"), ele.byId("materialtable"), true);\n    CABLES.UI.Collapsable.setup(ele.byId("groupAnims"), ele.byId("sectionAnim"), true);\n    CABLES.UI.Collapsable.setup(ele.byId("groupMeshes"), ele.byId("meshestable"), true);\n    CABLES.UI.Collapsable.setup(ele.byId("groupCameras"), ele.byId("sectionCameras"), true);\n    CABLES.UI.Collapsable.setup(ele.byId("groupImages"), ele.byId("sectionImages"), true);\n    CABLES.UI.Collapsable.setup(ele.byId("groupSkins"), ele.byId("sectionSkins"), true);\n    CABLES.UI.Collapsable.setup(ele.byId("groupBinary"), ele.byId("sectionBinary"), true);\n    CABLES.UI.Collapsable.setup(ele.byId("groupTiming"), ele.byId("sectionTiming"), true);\n\n    gui.maintabPanel.show(true);\n}\n\nfunction readableSize(n)\n{\n    if (n > 1024) return Math.round(n / 1024) + " kb";\n    if (n > 1024 * 500) return Math.round(n / 1024) + " mb";\n    else return n + " bytes";\n}\n',inc_skin_js:'const GltfSkin = class\n{\n    constructor(node)\n    {\n        this._mod = null;\n        this._node = node;\n        this._lastTime = 0;\n        this._matArr = [];\n        this._m = mat4.create();\n        this._invBindMatrix = mat4.create();\n        this.identity = true;\n    }\n\n    renderFinish(cgl)\n    {\n        cgl.popModelMatrix();\n        this._mod.unbind();\n    }\n\n    renderStart(cgl, time)\n    {\n        if (!this._mod)\n        {\n            this._mod = new CGL.ShaderModifier(cgl, op.name + this._node.name);\n\n            this._mod.addModule({\n                "priority": -2,\n                "name": "MODULE_VERTEX_POSITION",\n                "srcHeadVert": attachments.skin_head_vert || "",\n                "srcBodyVert": attachments.skin_vert || ""\n            });\n\n            this._mod.addUniformVert("m4[]", "MOD_boneMats", []);// bohnenmatze\n            const tr = vec3.create();\n        }\n\n        const skinIdx = this._node.skin;\n        const arrLength = gltf.json.skins[skinIdx].joints.length * 16;\n\n        // if (this._lastTime != time || !time)\n        {\n            // this._lastTime=inTime.get();\n            if (this._matArr.length != arrLength) this._matArr.length = arrLength;\n\n            for (let i = 0; i < gltf.json.skins[skinIdx].joints.length; i++)\n            {\n                const i16 = i * 16;\n                const jointIdx = gltf.json.skins[skinIdx].joints[i];\n                const nodeJoint = gltf.nodes[jointIdx];\n\n                for (let j = 0; j < 16; j++)\n                    this._invBindMatrix[j] = gltf.accBuffers[gltf.json.skins[skinIdx].inverseBindMatrices][i16 + j];\n\n                mat4.mul(this._m, nodeJoint.modelMatAbs(), this._invBindMatrix);\n\n                for (let j = 0; j < this._m.length; j++) this._matArr[i16 + j] = this._m[j];\n            }\n\n            this._mod.setUniformValue("MOD_boneMats", this._matArr);\n            this._lastTime = time;\n        }\n\n        this._mod.define("SKIN_NUM_BONES", gltf.json.skins[skinIdx].joints.length);\n        this._mod.bind();\n\n        // draw mesh...\n        cgl.pushModelMatrix();\n        if (this.identity)mat4.identity(cgl.mMatrix);\n    }\n};\n',skin_vert:"int index=int(attrJoints.x);\nvec4 newPos = (MOD_boneMats[index] * pos) * attrWeights.x;\nvec3 newNorm = (vec4((MOD_boneMats[index] * vec4(norm.xyz, 0.0)) * attrWeights.x).xyz);\n\nindex=int(attrJoints.y);\nnewPos += (MOD_boneMats[index] * pos) * attrWeights.y;\nnewNorm = (vec4((MOD_boneMats[index] * vec4(norm.xyz, 0.0)) * attrWeights.y).xyz)+newNorm;\n\nindex=int(attrJoints.z);\nnewPos += (MOD_boneMats[index] * pos) * attrWeights.z;\nnewNorm = (vec4((MOD_boneMats[index] * vec4(norm.xyz, 0.0)) * attrWeights.z).xyz)+newNorm;\n\nindex=int(attrJoints.w);\nnewPos += (MOD_boneMats[index] * pos) * attrWeights.w ;\nnewNorm = (vec4((MOD_boneMats[index] * vec4(norm.xyz, 0.0)) * attrWeights.w).xyz)+newNorm;\n\npos=newPos;\n\nnorm=normalize(newNorm.xyz);\n\n\n",skin_head_vert:"\nIN vec4 attrWeights;\nIN vec4 attrJoints;\nUNI mat4 MOD_boneMats[SKIN_NUM_BONES];\n"};const i=class{constructor(e,t){this.node=t;this.name=t.name;this.config=e.json.cameras[t.camera];this.pos=vec3.create();this.quat=quat.create();this.vCenter=vec3.create();this.vUp=vec3.create();this.vMat=mat4.create()}updateAnim(e){if(this.node&&this.node._animTrans){vec3.set(this.pos,this.node._animTrans[0].getValue(e),this.node._animTrans[1].getValue(e),this.node._animTrans[2].getValue(e));quat.set(this.quat,this.node._animRot[0].getValue(e),this.node._animRot[1].getValue(e),this.node._animRot[2].getValue(e),this.node._animRot[3].getValue(e))}}start(e){if(g.tempData.shadowPass)return;this.updateAnim(e);const t=g.getViewPort()[2]/g.getViewPort()[3];g.pushPMatrix();g.pushViewMatrix();let n=mat4.create();mat4.invert(n,this.node.modelMatAbs());this.vMat=n;mat4.identity(g.vMatrix);mat4.mul(g.vMatrix,g.vMatrix,n)}end(){if(g.tempData.shadowPass)return;g.popPMatrix();g.popViewMatrix()}};const k=8;const M=class{constructor(){this.json={};this.accBuffers=[];this.meshes=[];this.nodes=[];this.shaders=[];this.timing=[];this.cams=[];this.startTime=performance.now();this.bounds=new CABLES.CG.BoundingBox;this.loaded=Date.now();this.accBuffersDelete=[]}getNode(t){for(let e=0;e<this.nodes.length;e++){if(this.nodes[e].name==t)return this.nodes[e]}}unHideAll(){for(let e=0;e<this.nodes.length;e++){this.nodes[e].unHide()}}};function E(e){if(window.TextDecoder)return new TextDecoder("utf-8").decode(e);let t,n,i,r;let s,a;t="";i=e.length;n=0;while(n<i){r=e[n++];switch(r>>4){case 0:case 1:case 2:case 3:case 4:case 5:case 6:case 7:t+=String.fromCharCode(r);break;case 12:case 13:s=e[n++];t+=String.fromCharCode((r&31)<<6|s&63);break;case 14:s=e[n++];a=e[n++];t+=String.fromCharCode((r&15)<<12|(s&63)<<6|(a&63)<<0);break}}return t}function v(e,t,n,i){const r={};if(i>=e.byteLength){_.log("could not read chunk...");return}r.size=e.getUint32(i+0,D);r.type=E(t.subarray(i+4,i+4+4));if(r.type=="BIN\0"){r.dataView=new DataView(n,i+8,r.size)}else if(r.type=="JSON"){const s=E(t.subarray(i+8,i+8+r.size));try{const a=JSON.parse(s);r.data=a;se.set(a.asset.generator)}catch(e){}}else{_.warn("unknown type",r.type)}return r}function P(t){const i={};for(let e=0;e<t.json.animations.length;e++){const r=t.json.animations[e];for(let e=0;e<r.channels.length;e++){const s=r.channels[e];const a=t.nodes[s.target.node];const o=r.samplers[s.sampler];const n=t.json.accessors[o.input];const l=t.accBuffers[o.input];const h=t.json.accessors[o.output];const u=t.accBuffers[o.output];t.accBuffersDelete.push(o.output,o.input);if(l&&u){let n=1;if(h.type=="VEC2")n=2;else if(h.type=="VEC3")n=3;else if(h.type=="VEC4")n=4;else _.warn("unknown accOut.type",h.type);const f=[];i[r.name]=true;for(let e=0;e<n;e++){const c=new CABLES.Anim;f.push(c)}if(o.interpolation==="LINEAR"){}else if(o.interpolation==="STEP")for(let e=0;e<n;e++)f[e].defaultEasing=CABLES.EASING_ABSOLUTE;else if(o.interpolation==="CUBICSPLINE")for(let e=0;e<n;e++)f[e].defaultEasing=CABLES.EASING_CUBICSPLINE;else _.warn("unknown interpolation",o.interpolation);if(l[0]!==0)for(let e=0;e<n;e++)f[e].setValue(0,u[0*n+e]);for(let t=0;t<l.length;t++){x=Math.max(l[t],x);for(let e=0;e<n;e++){if(f[e].defaultEasing===CABLES.EASING_CUBICSPLINE){const d=t*n*3+e;const m=f[e].setValue(l[t],u[d+n]);m.bezTangIn=u[d];m.bezTangOut=u[d+n*2]}else{f[e].setValue(l[t],u[t*n+e])}}}a.setAnim(s.target.path,r.name,f)}else{_.warn("loadAmins bufferIn undefined ",l===undefined);_.warn("loadAmins bufferOut undefined ",u===undefined);_.warn("loadAmins ",o,h);_.warn("loadAmins num accBuffers",t.accBuffers.length);_.warn("loadAmins num accessors",t.json.accessors.length)}}}t.uniqueAnimNames=i;fe.setRef(Object.keys(i))}function U(n){if(!n||!n.json.cameras)return;n.cameras=n.cameras||[];for(let t=0;t<n.nodes.length;t++){if(n.nodes[t].hasOwnProperty("camera")){const e=new i(n,n.nodes[t]);n.cameras.push(e)}}}function V(){if(!window.DracoDecoder){setTimeout(()=>{V()},100)}L()}function G(e){let r=0,t=0;const s=new M;s.timing.push(["Start parsing",Math.round(performance.now()-s.startTime)]);if(!e)return;const n=new Uint8Array(e);let i=0;const a=E(n.subarray(i,4));i+=4;if(a!="glTF")return;s.timing.push(["dataview",Math.round(performance.now()-s.startTime)]);const o=new DataView(e);const l=o.getUint32(i,D);i+=4;const h=o.getUint32(i,D);i+=4;ae.set(l);const u=[];s.chunks=u;u.push(v(o,n,e,i));i+=u[0].size+k;s.json=u[0].data;s.cables={fileUrl:B.get(),shortFileName:CABLES.basename(B.get())};ue.set(s.json);oe.set(s.json.extensionsUsed||[]);let f=v(o,n,e,i);while(f){u.push(f);i+=f.size+k;f=v(o,n,e,i)}s.chunks=u;const c=u[0].data.bufferViews;const d=u[0].data.accessors;s.timing.push(["Parse buffers",Math.round(performance.now()-s.startTime)]);if(s.json.extensionsUsed&&s.json.extensionsUsed.indexOf("KHR_draco_mesh_compression")>-1){if(!window.DracoDecoder){_.setUiError("gltfdraco","GLTF draco compression lib not found / add draco op to your patch!");V();return s}else{s.useDraco=true}}_.setUiError("gltfdraco",null);if(c){for(t=0;t<d.length;t++){const m=d[t];const g=c[m.bufferView];let i=0;if(m.type=="SCALAR")i=1;else if(m.type=="VEC2")i=2;else if(m.type=="VEC3")i=3;else if(m.type=="VEC4")i=4;else if(m.type=="MAT4")i=16;else console.error("unknown accessor type",m.type);if(u[1].dataView){if(g){const p=m.count*i;let e=(g.byteOffset||0)+(m.byteOffset||0);let t=g.byteStride||0;let n=null;if(m.componentType==5126||m.componentType==5125){t=t||4;const F=m.componentType==5125;if(F)n=new Uint32Array(p);else n=new Float32Array(p);for(r=0;r<p;r++){if(F)n[r]=u[1].dataView.getUint32(e,D);else n[r]=u[1].dataView.getFloat32(e,D);if(t!=4&&(r+1)%i===0)e+=t-i*4;e+=4}}else if(m.componentType==5123){t=t||2;n=new Uint16Array(p);for(r=0;r<p;r++){n[r]=u[1].dataView.getUint16(e,D);if(t!=2&&(r+1)%i===0)e+=t-i*2;e+=2}}else if(m.componentType==5121){t=t||1;n=new Uint8Array(p);for(r=0;r<p;r++){n[r]=u[1].dataView.getUint8(e,D);if(t!=1&&(r+1)%i===0)e+=t-i*1;e+=1}}else{console.error("unknown component type",m.componentType)}s.accBuffers.push(n)}else{}}}}s.timing.push(["Parse mesh groups",Math.round(performance.now()-s.startTime)]);s.json.meshes=s.json.meshes||[];if(s.json.meshes){for(t=0;t<s.json.meshes.length;t++){const A=new z(s,s.json.meshes[t]);s.meshes.push(A)}}s.timing.push(["Parse nodes",Math.round(performance.now()-s.startTime)]);for(t=0;t<s.json.nodes.length;t++){if(s.json.nodes[t].children)for(r=0;r<s.json.nodes[t].children.length;r++){s.json.nodes[s.json.nodes[t].children[r]].isChild=true}}for(t=0;t<s.json.nodes.length;t++){const C=new X(s.json.nodes[t],s);s.nodes.push(C)}for(t=0;t<s.nodes.length;t++){const C=s.nodes[t];if(!C.children)continue;for(let e=0;e<C.children.length;e++){s.nodes[C.children[e]].parent=C}}for(t=0;t<s.nodes.length;t++){s.nodes[t].initSkin()}T=true;s.timing.push(["load anims",Math.round(performance.now()-s.startTime)]);if(s.json.animations)P(s);s.timing.push(["load cameras",Math.round(performance.now()-s.startTime)]);if(s.json.cameras)U(s);s.timing.push(["finished",Math.round(performance.now()-s.startTime)]);return s}let j=class{constructor(e,n,s,a){this.POINTS=0;this.LINES=1;this.LINE_LOOP=2;this.LINE_STRIP=3;this.TRIANGLES=4;this.TRIANGLE_STRIP=5;this.TRIANGLE_FAN=6;this.test=0;this.name=e;this.submeshIndex=0;this.material=n.material;this.mesh=null;this.geom=new CGL.Geometry("gltf_"+this.name);this.geom.verticesIndices=[];this.bounds=null;this.primitive=4;if(n.hasOwnProperty("mode"))this.primitive=n.mode;if(n.hasOwnProperty("indices"))this.geom.verticesIndices=s.accBuffers[n.indices];s.loadingMeshes=s.loadingMeshes||0;s.loadingMeshes++;this.materialJson=this._matPbrMetalness=this._matPbrRoughness=this._matDiffuseColor=null;if(s.json.materials){if(this.material!=-1)this.materialJson=s.json.materials[this.material];if(this.materialJson&&this.materialJson.pbrMetallicRoughness){if(!this.materialJson.pbrMetallicRoughness.hasOwnProperty("baseColorFactor")){this._matDiffuseColor=[1,1,1,1]}else{this._matDiffuseColor=this.materialJson.pbrMetallicRoughness.baseColorFactor}this._matDiffuseColor=this.materialJson.pbrMetallicRoughness.baseColorFactor;if(!this.materialJson.pbrMetallicRoughness.hasOwnProperty("metallicFactor")){this._matPbrMetalness=1}else{this._matPbrMetalness=this.materialJson.pbrMetallicRoughness.metallicFactor||null}if(!this.materialJson.pbrMetallicRoughness.hasOwnProperty("roughnessFactor")){this._matPbrRoughness=1}else{this._matPbrRoughness=this.materialJson.pbrMetallicRoughness.roughnessFactor||null}}}if(s.useDraco&&n.extensions.KHR_draco_mesh_compression){const i=s.chunks[0].data.bufferViews[n.extensions.KHR_draco_mesh_compression.bufferView];const r=i.byteLength;const o=new Int8Array(r);let t=i.byteOffset||0;for(let e=0;e<r;e++){o[e]=s.chunks[1].dataView.getInt8(t,D);t++}const l=window.DracoDecoder;l.decodeGeometry(o.buffer,t=>{const n=new CGL.Geometry("draco mesh "+e);for(let e=0;e<t.attributes.length;e++){const i=t.attributes[e];if(i.name==="position")n.vertices=i.array;else if(i.name==="normal")n.vertexNormals=i.array;else if(i.name==="uv")n.texCoords=i.array;else if(i.name==="color")n.vertexColors=this.calcVertexColors(i.array);else if(i.name==="joints")n.setAttribute("attrJoints",Array.from(i.array),4);else if(i.name==="weights"){const r=new Float32Array(i.array.length/i.itemSize*4);for(let t=0;t<i.array.length/i.itemSize;t++){r[t*4]=r[t*4+1]=r[t*4+2]=r[t*4+3]=0;for(let e=0;e<i.itemSize;e++)r[t*4+e]=i.array[t*i.itemSize+e]}n.setAttribute("attrWeights",r,4)}else _.logWarn("unknown draco attrib",i)}t.attributes=null;n.verticesIndices=t.index.array;this.setGeom(n);this.mesh=null;s.loadingMeshes--;s.timing.push(["draco decode",Math.round(performance.now()-s.startTime)]);if(a)a(this)},e=>{_.logError(e)})}else{s.loadingMeshes--;this.fillGeomAttribs(s,this.geom,n.attributes);if(n.targets){for(let e=0;e<n.targets.length;e++){let t=this.geom.copy();if(n.hasOwnProperty("indices"))t.verticesIndices=s.accBuffers[n.indices];this.fillGeomAttribs(s,t,n.targets[e],false);{for(let e=0;e<t.vertices.length;e++)t.vertices[e]+=this.geom.vertices[e];t.calculateNormals();for(let e=0;e<t.vertices.length;e++)t.vertices[e]-=this.geom.vertices[e]}this.geom.morphTargets.push(t)}}if(a)a(this)}}_linearToSrgb(e){if(e<=0)return 0;else if(e>=1)return 1;else if(e<.0031308)return e*12.92;else return e**(1/2.2)*1.055-.055}calcVertexColors(n){let i=null;if(n instanceof Float32Array){let t=false;for(let e=0;e<n.length;e++){if(n[e]>1){t=true;continue}}if(t)for(let e=0;e<n.length;e++)n[e]/=65535;i=n}else if(n instanceof Uint16Array){const t=new Float32Array(n.length);for(let e=0;e<n.length;e++)t[e]=n[e]/65535;i=t}else i=n;for(let e=0;e<i.length;e++){i[e]=this._linearToSrgb(i[e])}return i}fillGeomAttribs(e,t,n,i){if(n.hasOwnProperty("POSITION"))t.vertices=e.accBuffers[n.POSITION];if(n.hasOwnProperty("NORMAL"))t.vertexNormals=e.accBuffers[n.NORMAL];if(n.hasOwnProperty("TANGENT"))t.tangents=e.accBuffers[n.TANGENT];if(n.hasOwnProperty("COLOR_0"))t.vertexColors=this.calcVertexColors(e.accBuffers[n.COLOR_0]);if(n.hasOwnProperty("COLOR_1"))t.setAttribute("attrVertColor1",this.calcVertexColors(e.accBuffers[n.COLOR_1]),4);if(n.hasOwnProperty("COLOR_2"))t.setAttribute("attrVertColor2",this.calcVertexColors(e.accBuffers[n.COLOR_2]),4);if(n.hasOwnProperty("COLOR_3"))t.setAttribute("attrVertColor3",this.calcVertexColors(e.accBuffers[n.COLOR_3]),4);if(n.hasOwnProperty("COLOR_4"))t.setAttribute("attrVertColor4",this.calcVertexColors(e.accBuffers[n.COLOR_4]),4);if(n.hasOwnProperty("TEXCOORD_0"))t.texCoords=e.accBuffers[n.TEXCOORD_0];if(n.hasOwnProperty("TEXCOORD_1"))t.setAttribute("attrTexCoord1",e.accBuffers[n.TEXCOORD_1],2);if(n.hasOwnProperty("TEXCOORD_2"))t.setAttribute("attrTexCoord2",e.accBuffers[n.TEXCOORD_2],2);if(n.hasOwnProperty("TEXCOORD_3"))t.setAttribute("attrTexCoord3",e.accBuffers[n.TEXCOORD_3],2);if(n.hasOwnProperty("TEXCOORD_4"))t.setAttribute("attrTexCoord4",e.accBuffers[n.TEXCOORD_4],2);if(n.hasOwnProperty("WEIGHTS_0")){t.setAttribute("attrWeights",e.accBuffers[n.WEIGHTS_0],4)}if(n.hasOwnProperty("JOINTS_0")){if(!e.accBuffers[n.JOINTS_0])console.log("no !gltf.accBuffers[attribs.JOINTS_0]");t.setAttribute("attrJoints",e.accBuffers[n.JOINTS_0],4)}if(n.hasOwnProperty("POSITION"))e.accBuffersDelete.push(n.POSITION);if(n.hasOwnProperty("NORMAL"))e.accBuffersDelete.push(n.NORMAL);if(n.hasOwnProperty("TEXCOORD_0"))e.accBuffersDelete.push(n.TEXCOORD_0);if(n.hasOwnProperty("TANGENT"))e.accBuffersDelete.push(n.TANGENT);if(n.hasOwnProperty("COLOR_0"))e.accBuffersDelete.push(n.COLOR_0);if(n.hasOwnProperty("COLOR_0"))e.accBuffersDelete.push(n.COLOR_0);if(n.hasOwnProperty("COLOR_1"))e.accBuffersDelete.push(n.COLOR_1);if(n.hasOwnProperty("COLOR_2"))e.accBuffersDelete.push(n.COLOR_2);if(n.hasOwnProperty("COLOR_3"))e.accBuffersDelete.push(n.COLOR_3);if(n.hasOwnProperty("TEXCOORD_1"))e.accBuffersDelete.push(n.TEXCOORD_1);if(n.hasOwnProperty("TEXCOORD_2"))e.accBuffersDelete.push(n.TEXCOORD_2);if(n.hasOwnProperty("TEXCOORD_3"))e.accBuffersDelete.push(n.TEXCOORD_3);if(n.hasOwnProperty("TEXCOORD_4"))e.accBuffersDelete.push(n.TEXCOORD_4);if(i!==false)if(t&&t.verticesIndices)this.setGeom(t)}setGeom(n){if(ee.get()=="X-ZY"){for(let t=0;t<n.vertexNormals.length;t+=3){let e=n.vertexNormals[t+2];n.vertexNormals[t+2]=n.vertexNormals[t+1];n.vertexNormals[t+1]=-e}}if(te.get()=="XZ-Y"){for(let t=0;t<n.vertices.length;t+=3){let e=n.vertices[t+2];n.vertices[t+2]=-n.vertices[t+1];n.vertices[t+1]=e}}if(this.primitive==this.TRIANGLES){if(!n.vertexNormals.length||f.get())n.calculateNormals();if((!n.biTangents||n.biTangents.length==0)&&n.tangents){const t=vec3.create();const e=vec3.create();const i=n.tangents;n.tangents=new Float32Array(i.length/4*3);n.biTangents=new Float32Array(i.length/4*3);for(let e=0;e<i.length;e+=4){const r=e/4*3;vec3.cross(t,[n.vertexNormals[r],n.vertexNormals[r+1],n.vertexNormals[r+2]],[i[e],i[e+1],i[e+2]]);vec3.div(t,t,[i[e+3],i[e+3],i[e+3]]);vec3.normalize(t,t);n.biTangents[r+0]=t[0];n.biTangents[r+1]=t[1];n.biTangents[r+2]=t[2];n.tangents[r+0]=i[e+0];n.tangents[r+1]=i[e+1];n.tangents[r+2]=i[e+2]}}if(n.tangents.length===0||f.get())n.calcTangentsBitangents()}this.geom=n;this.bounds=n.getBounds()}render(n,t,i){if(!this.mesh&&this.geom&&this.geom.verticesIndices){let e=this.geom;if(this.geom.vertices.length/3>64e3){e=this.geom.copy();e.unIndex(false,true)}let t;if(this.primitive==this.TRIANGLES)t=n.gl.TRIANGLES;else if(this.primitive==this.LINES)t=n.gl.LINES;else if(this.primitive==this.LINE_STRIP)t=n.gl.LINE_STRIP;else if(this.primitive==this.POINTS)t=n.gl.POINTS;else{_.logWarn("unknown primitive type",this)}this.mesh=new CGL.Mesh(n,e,t)}else{if(this.geom&&this.geom.morphTargets.length){this.morphGeom=this.geom.copy();this.test=S*11.7;if(this.test>=this.geom.morphTargets.length-1)this.test=0;const l=this.geom.morphTargets[Math.floor(this.test)];const h=this.geom.morphTargets[Math.floor(this.test+1)];if(l&&l.vertices&&h){if(this.morphGeom.vertexNormals.length!=l.vertexNormals.length)this.morphGeom.vertexNormals=new Float32Array(l.vertexNormals.length);const u=this.test%1;for(let e=0;e<this.morphGeom.vertices.length;e++){this.morphGeom.vertices[e]=this.geom.vertices[e]+(1-u)*l.vertices[e]+u*h.vertices[e];this.morphGeom.vertexNormals[e]=(1-u)*l.vertexNormals[e]+u*h.vertexNormals[e]}this.mesh.updateNormals(this.morphGeom);this.mesh.updateVertices(this.morphGeom)}}let e=!t&&this.material!=-1&&y.shaders[this.material];if(i)e=false;if(e)n.pushShader(y.shaders[this.material]);const r=n.getShader()||{};const s=r.uniformColorDiffuse;const a=r.uniformPbrMetalness;const o=r.uniformPbrRoughness;if(!y.shaders[this.material]&&ie.get()){if(s&&this._matDiffuseColor){this._matDiffuseColorOrig=[s.getValue()[0],s.getValue()[1],s.getValue()[2],s.getValue()[3]];s.setValue(this._matDiffuseColor)}if(a)if(this._matPbrMetalness!=null){this._matPbrMetalnessOrig=a.getValue();a.setValue(this._matPbrMetalness)}else a.setValue(0);if(o)if(this._matPbrRoughness!=null){this._matPbrRoughnessOrig=o.getValue();o.setValue(this._matPbrRoughness)}else{o.setValue(0)}}if(this.mesh)this.mesh.render(n.getShader(),t);if(ie.get()){if(s&&this._matDiffuseColor)s.setValue(this._matDiffuseColorOrig);if(a&&this._matPbrMetalnessOrig!=undefined)a.setValue(this._matPbrMetalnessOrig);if(o&&this._matPbrRoughnessOrig!=undefined)o.setValue(this._matPbrRoughnessOrig)}if(e)n.popShader()}}};const z=class{constructor(t,e){this.bounds=new CABLES.CG.BoundingBox;this.meshes=[];this.name=e.name;const n=e.primitives;for(let e=0;e<n.length;e++){const i=new j(this.name,n[e],t,e=>{this.bounds.apply(e.bounds)});i.submeshIndex=e;this.meshes.push(i)}}render(t,n,i,r){for(let e=0;e<this.meshes.length;e++){const s=y.shaders[this.meshes[e].material];if(!n&&s)t.pushShader(y.shaders[this.meshes[e].material]);if(i)i.renderStart(t,r);this.meshes[e].render(t,n,i,r);if(i)i.renderFinish(t);if(!n&&s)t.popShader()}}};const X=class{constructor(e,t){this.isChild=e.isChild||false;this.name=e.name;if(e.hasOwnProperty("camera"))this.camera=e.camera;this.hidden=false;this.mat=mat4.create();this._animMat=mat4.create();this._tempMat=mat4.create();this._tempQuat=quat.create();this._tempRotmat=mat4.create();this.mesh=null;this.children=[];this._node=e;this._gltf=t;this.absMat=mat4.create();this.addTranslate=null;this._tempAnimScale=null;this.addMulMat=null;this.updateMatrix();this._animActions={};this.skinRenderer=null;this.copies=[]}get skin(){if(this._node.hasOwnProperty("skin"))return this._node.skin;else return-1}copy(){this.isCopy=true;const e=new X(this._node,this._gltf);e.copyOf=this;e._animActions=this._animActions;e.children=this.children;e.skinRenderer=new Z(e);this.updateMatrix();return e}hasSkin(){if(this._node.hasOwnProperty("skin"))return this._gltf.json.skins[this._node.skin].name||"unknown";return false}initSkin(){if(this.skin>-1){this.skinRenderer=new Z(this)}}updateMatrix(){mat4.identity(this.mat);if(this._node.translation)mat4.translate(this.mat,this.mat,this._node.translation);if(this._node.rotation){const e=mat4.create();this._rot=this._node.rotation;mat4.fromQuat(e,this._node.rotation);mat4.mul(this.mat,this.mat,e)}if(this._node.scale){this._scale=this._node.scale;mat4.scale(this.mat,this.mat,this._scale)}if(this._node.hasOwnProperty("mesh")){this.mesh=this._gltf.meshes[this._node.mesh];if(this.isCopy){console.log(this.mesh)}}if(this._node.children){for(let e=0;e<this._node.children.length;e++){this._gltf.json.nodes[e].isChild=true;if(this._gltf.nodes[this._node.children[e]])this._gltf.nodes[this._node.children[e]].isChild=true;this.children.push(this._node.children[e])}}}unHide(){this.hidden=false;for(let e=0;e<this.children.length;e++)if(this.children[e].unHide)this.children[e].unHide()}calcBounds(t,e,n){const i=mat4.create();if(e)mat4.copy(i,e);if(this.mat)mat4.mul(i,i,this.mat);if(this.mesh){const r=this.mesh.bounds.copy();r.mulMat4(i);n.apply(r);if(n.changed){A.push(r._min[0]||0,r._min[1]||0,r._min[2]||0,r._max[0]||0,r._max[1]||0,r._max[2]||0)}}for(let e=0;e<this.children.length;e++){if(t.nodes[this.children[e]]&&t.nodes[this.children[e]].calcBounds){const s=t.nodes[this.children[e]].calcBounds(t,i,n);n.apply(s)}}if(n.changed)return n;else return null}setAnimAction(t){if(!t)return;this._currentAnimaction=t;if(t&&!this._animActions[t]){return null}for(let e in this._animActions[t]){if(e=="translation")this._animTrans=this._animActions[t][e];else if(e=="rotation")this._animRot=this._animActions[t][e];else if(e=="scale")this._animScale=this._animActions[t][e];else console.warn("unknown anim path",e,this._animActions[t][e])}}setAnim(e,t,n){if(!e||!t||!n)return;this._animActions[t]=this._animActions[t]||{};if(this._animActions[t][e])_.warn("animation action path already exists",t,e,this._animActions[t][e]);this._animActions[t][e]=n;if(e=="translation")this._animTrans=n;else if(e=="rotation")this._animRot=n;else if(e=="scale")this._animScale=n;else console.warn("unknown anim path",e,n)}modelMatLocal(){return this._animMat||this.mat}modelMatAbs(){return this.absMat}transform(e,t){if(!t&&t!=0)t=S;this._lastTimeTrans=t;pe++;if(!this._animTrans&&!this._animRot&&!this._animScale){mat4.mul(e.mMatrix,e.mMatrix,this.mat);this._animMat=null}else{this._animMat=this._animMat||mat4.create();mat4.identity(this._animMat);const n=true;if(n&&this._animTrans){mat4.translate(this._animMat,this._animMat,[this._animTrans[0].getValue(t),this._animTrans[1].getValue(t),this._animTrans[2].getValue(t)])}else if(this._node.translation)mat4.translate(this._animMat,this._animMat,this._node.translation);if(n&&this._animRot){if(this._animRot[0].defaultEasing==CABLES.EASING_LINEAR)CABLES.Anim.slerpQuaternion(t,this._tempQuat,this._animRot[0],this._animRot[1],this._animRot[2],this._animRot[3]);else if(this._animRot[0].defaultEasing==CABLES.EASING_ABSOLUTE){this._tempQuat[0]=this._animRot[0].getValue(t);this._tempQuat[1]=this._animRot[1].getValue(t);this._tempQuat[2]=this._animRot[2].getValue(t);this._tempQuat[3]=this._animRot[3].getValue(t)}else if(this._animRot[0].defaultEasing==CABLES.EASING_CUBICSPLINE){CABLES.Anim.slerpQuaternion(t,this._tempQuat,this._animRot[0],this._animRot[1],this._animRot[2],this._animRot[3])}mat4.fromQuat(this._tempMat,this._tempQuat);mat4.mul(this._animMat,this._animMat,this._tempMat)}else if(this._rot){}if(n&&this._animScale){if(!this._tempAnimScale)this._tempAnimScale=[1,1,1];this._tempAnimScale[0]=this._animScale[0].getValue(t);this._tempAnimScale[1]=this._animScale[1].getValue(t);this._tempAnimScale[2]=this._animScale[2].getValue(t);mat4.scale(this._animMat,this._animMat,this._tempAnimScale)}else if(this._scale)mat4.scale(this._animMat,this._animMat,this._scale);mat4.mul(e.mMatrix,e.mMatrix,this._animMat)}if(this.addTranslate)mat4.translate(e.mMatrix,e.mMatrix,this.addTranslate);if(this.addMulMat)mat4.mul(e.mMatrix,e.mMatrix,this.addMulMat);mat4.copy(this.absMat,e.mMatrix)}render(t,n,i,r,s,a,o){if(!n)t.pushModelMatrix();if(o===undefined)o=y.time;if(!n||this.skinRenderer)this.transform(t,o);if(this.hidden&&!a){}else{if(this.skinRenderer){this.skinRenderer.time=o;if(!i)this.mesh.render(t,r,this.skinRenderer,o)}else{if(this.mesh&&!i)this.mesh.render(t,r,null,o)}}if(!s&&!this.hidden)for(let e=0;e<this.children.length;e++)if(y.nodes[this.children[e]])y.nodes[this.children[e]].render(t,n,i,r,s,a,o);if(!n)t.popModelMatrix()}};let C=null;function b(){if(C)gui.mainTabs.closeTab(C.id);C=null}function o(t){const n=[];for(let e=0;e<t.length;e++){n.push(Math.round(t[e]*1e3)/1e3)}return n.join(",")}function H(n,i,r){if(!y)return;n+='<tr class="row">';let s="";let a="";for(let t=1;t<r;t++){a+="&nbsp;&nbsp;&nbsp;";let e="identBg";if(t==1)e="identBgLevel0";s+='<td class="ident '+e+'" ><div style=""></div></td>'}let e=CABLES.uuid();n+=s;n+='<td colspan="'+(21-r)+'">';if(i.mesh&&i.mesh.meshes.length)n+='<span class="icon icon-cube"></span>&nbsp;';else n+='<span class="icon icon-box-select"></span> &nbsp;';n+=i.name+"</td><td></td>";if(i.mesh){n+="<td>";for(let e=0;e<i.mesh.meshes.length;e++){if(e>0)n+=", ";n+=i.mesh.meshes[e].name}n+="</td>";n+="<td>";n+=i.hasSkin()||"-";n+="</td>";n+="<td>";let t=0;for(let e=0;e<i.mesh.meshes.length;e++){if(t>0)n+=", ";if(y.json.materials&&i.mesh.meshes[e].hasOwnProperty("material")){if(y.json.materials[i.mesh.meshes[e].material]){n+=y.json.materials[i.mesh.meshes[e].material].name;t++}}}if(t==0)n+="none";n+="</td>"}else{n+="<td>-</td><td>-</td><td>-</td>"}n+="<td>";if(i._node.translation||i._node.rotation||i._node.scale){let e="";if(i._node.translation)e+="Translate: `"+o(i._node.translation)+"` || ";if(i._node.rotation)e+="Rotation: `"+o(i._node.rotation)+"` || ";if(i._node.scale)e+="Scale: `"+o(i._node.scale)+"` || ";n+='<span class="icon icon-gizmo info" data-info="'+e+'"></span> &nbsp;'}if(i._animRot||i._animScale||i._animTrans){let e="Animated: ";if(i._animRot)e+="Rot ";if(i._animScale)e+="Scale ";if(i._animTrans)e+="Trans ";n+='<span class="icon icon-clock info" data-info="'+e+'"></span>&nbsp;'}if(!i._node.translation&&!i._node.rotation&&!i._node.scale&&!i._animRot&&!i._animScale&&!i._animTrans)n+="-";n+="</td>";n+="<td>";let t="";if(i.hidden)t="node-hidden";n+="<a onclick=\"gui.corePatch().getOpById('"+_.id+"').exposeNode('"+i.name+"','transform')\" class=\"treebutton\">Transform</a>";n+=" <a onclick=\"gui.corePatch().getOpById('"+_.id+"').exposeNode('"+i.name+"','hierarchy')\" class=\"treebutton\">Hierarchy</a>";n+=" <a onclick=\"gui.corePatch().getOpById('"+_.id+"').exposeNode('"+i.name+'\')" class="treebutton">Node</a>';if(i.hasSkin())n+=" <a onclick=\"gui.corePatch().getOpById('"+_.id+"').exposeNode('"+i.name+'\',false,{skin:true});" class="treebutton">Skin</a>';n+="</td><td>";n+='&nbsp;<span class="icon iconhover icon-eye '+t+'" onclick="gui.corePatch().getOpById(\''+_.id+"').toggleNodeVisibility('"+i.name+"');this.classList.toggle('node-hidden');\"></span>";n+="</td>";n+="</tr>";if(i.children){for(let e=0;e<i.children.length;e++)n=H(n,y.nodes[i.children[e]],r+1)}return n}function W(t,e){let n="<tr>";n+=" <td>"+e+"</td>";n+=" <td>"+t.name+"</td>";n+=" <td>";const i=JSON.stringify(t,null,4).replaceAll('"',"").replaceAll("\n","<br/>");n+="<span class=\"icon icon-info\" onclick=\"new CABLES.UI.ModalDialog({ 'html': '<pre>"+i+"</pre>', 'title': '"+t.name+"' });\"></span>&nbsp;";if(t.pbrMetallicRoughness&&t.pbrMetallicRoughness.baseColorFactor){let e="";e+=""+Math.round(t.pbrMetallicRoughness.baseColorFactor[0]*255);e+=","+Math.round(t.pbrMetallicRoughness.baseColorFactor[1]*255);e+=","+Math.round(t.pbrMetallicRoughness.baseColorFactor[2]*255);n+='<div style="width:15px;height:15px;background-color:rgb('+e+');display:inline-block">&nbsp;</a>'}n+=' <td style="">'+(y.shaders[e]?"-":"<a onclick=\"gui.corePatch().getOpById('"+_.id+"').assignMaterial('"+t.name+'\')" class="treebutton">Assign</a>')+"<td>";n+="<td>";n+="</tr>";return n}function e(){if(!y)return;const e=performance.now();const r={};let s='<div style="overflow:scroll;width:100%;height:100%">';s+='File: <a href="'+CABLES.platform.getCablesUrl()+"/asset/patches/?filename="+B.get()+'" target="_blank">'+CABLES.basename(B.get())+"</a><br/>";s+="Generator:"+y.json.asset.generator;let t=0;if(y.json.nodes)t=y.json.nodes.length;s+='<div id="groupNodes">Nodes ('+t+")</div>";s+='<table id="sectionNodes" class="table treetable">';s+="<tr>";s+=' <th colspan="21">Name</th>';s+=" <th>Mesh</th>";s+=" <th>Skin</th>";s+=" <th>Material</th>";s+=" <th>Transform</th>";s+=" <th>Expose</th>";s+=" <th></th>";s+="</tr>";for(let e=0;e<y.nodes.length;e++){if(!y.nodes[e].isChild)s=H(s,y.nodes[e],1)}s+="</table>";let n=0;if(y.json.materials)n=y.json.materials.length;s+='<div id="groupMaterials">Materials ('+n+")</div>";if(!y.json.materials||y.json.materials.length==0){}else{s+='<table id="materialtable"  class="table treetable">';s+="<tr>";s+=" <th>Index</th>";s+=" <th>Name</th>";s+=" <th>Color</th>";s+=" <th>Function</th>";s+=" <th></th>";s+="</tr>";for(let e=0;e<y.json.materials.length;e++){s+=W(y.json.materials[e],e)}s+="</table>"}s+='<div id="groupMeshes">Meshes ('+y.json.meshes.length+")</div>";s+='<table id="meshestable"  class="table treetable">';s+="<tr>";s+=" <th>Name</th>";s+=" <th>Node</th>";s+=" <th>Material</th>";s+=" <th>Vertices</th>";s+=" <th>Attributes</th>";s+="</tr>";let a=[];r.meshes=0;for(let i=0;i<y.json.meshes.length;i++){s+="<tr>";s+="<td>"+y.json.meshes[i].name+"</td>";s+="<td>";let e=0;let t="";for(var o=0;o<y.json.nodes.length;o++){if(y.json.nodes[o].mesh==i){e++;if(e==1){t=y.json.nodes[o].name}}}if(e>1)s+=e+" nodes ("+t+" ...)";else s+=t;s+="</td>";s+="<td>";for(var o=0;o<y.json.meshes[i].primitives.length;o++){if(y.json.meshes[i].primitives[o].hasOwnProperty("material")){if(y.json.materials[y.json.meshes[i]]){s+=y.json.materials[y.json.meshes[i].primitives[o].material].name+" "}}else s+="None"}s+="</td>";s+="<td>";let n=0;for(var o=0;o<y.json.meshes[i].primitives.length;o++){if(y.json.meshes[i].primitives[o].attributes.POSITION!=undefined){let e=parseInt(y.json.accessors[y.json.meshes[i].primitives[o].attributes.POSITION].count);n+=e;s+=""+e+"<br/>"}else s+="-<br/>"}if(y.json.meshes[i].primitives.length>0)s+="="+n;s+="</td>";s+='<td style="vertical-align:top;">';for(let e=0;e<y.json.meshes[i].primitives.length;e++){s+=Object.keys(y.json.meshes[i].primitives[e].attributes);s+=" <a onclick=\"gui.corePatch().getOpById('"+_.id+"').exposeGeom('"+y.json.meshes[i].name+"',"+e+')" class="treebutton">Geometry</a>';s+="<br/>"}s+="</td>";s+="</tr>";for(let t=0;t<y.json.meshes[i].primitives.length;t++){const m=y.json.accessors[y.json.meshes[i].primitives[t].indices];if(m){let e=m.bufferView;if(a.indexOf(e)==-1){a.push(e);if(y.json.bufferViews[e])r.meshes+=y.json.bufferViews[e].byteLength}}for(let e in y.json.meshes[i].primitives[t].attributes){const g=y.json.meshes[i].primitives[t].attributes[e];const p=y.json.accessors[g].bufferView;if(a.indexOf(p)==-1){a.push(p);if(y.json.bufferViews[p])r.meshes+=y.json.bufferViews[p].byteLength}}}}s+="</table>";let i=0;let l=0;if(y.json.animations){l=y.json.animations.length;for(let e=0;e<y.json.animations.length;e++)i+=y.json.animations[e].samplers.length}s+='<div id="groupAnims">Animations ('+l+"/"+i+")</div>";if(y.json.animations){s+='<table id="sectionAnim" class="table treetable">';s+="<tr>";s+="  <th>Name</th>";s+="  <th>Target node</th>";s+="  <th>Path</th>";s+="  <th>Interpolation</th>";s+="  <th>Keys</th>";s+="</tr>";r.animations=0;for(let n=0;n<y.json.animations.length;n++){for(let t=0;t<y.json.animations[n].samplers.length;t++){let e=y.json.accessors[y.json.animations[n].samplers[t].input].bufferView;if(a.indexOf(e)==-1){a.push(e);r.animations+=y.json.bufferViews[e].byteLength}e=y.json.accessors[y.json.animations[n].samplers[t].output].bufferView;if(a.indexOf(e)==-1){a.push(e);r.animations+=y.json.bufferViews[e].byteLength}}for(let e=0;e<y.json.animations[n].channels.length;e++){s+="<tr>";s+="  <td> Anim "+n+": "+y.json.animations[n].name+"</td>";s+="  <td>"+y.nodes[y.json.animations[n].channels[e].target.node].name+"</td>";s+="  <td>";s+=y.json.animations[n].channels[e].target.path+" ";s+="  </td>";const F=y.json.animations[n].channels[e].sampler;const A=y.json.animations[n].samplers[F];s+="  <td>"+A.interpolation+"</td>";s+="  <td>"+y.json.accessors[A.output].count;s+="</td>";s+="</tr>"}}s+="</table>"}else{}let h=0;if(y.json.images)h=y.json.images.length;s+='<div id="groupImages">Images ('+h+")</div>";if(y.json.images){s+='<table id="sectionImages" class="table treetable">';s+="<tr>";s+="  <th>name</th>";s+="  <th>type</th>";s+="  <th>func</th>";s+="</tr>";r.images=0;for(let t=0;t<y.json.images.length;t++){if(y.json.images[t].bufferView)r.images+=y.json.bufferViews[y.json.images[t].bufferView].byteLength;s+="<tr>";s+="<td>"+y.json.images[t].name+"</td>";s+="<td>"+y.json.images[t].mimeType+"</td>";s+="<td>";let e=y.json.images[t].name;if(e===undefined)e=y.json.images[t].bufferView;s+="<a onclick=\"gui.corePatch().getOpById('"+_.id+"').exposeTexture('"+e+'\')" class="treebutton">Expose</a>';s+="</td>";s+="<tr>"}s+="</table>"}let u=0;if(y.json.cameras)u=y.json.cameras.length;s+='<div id="groupCameras">Cameras ('+u+")</div>";if(y.json.cameras){s+='<table id="sectionCameras" class="table treetable">';s+="<tr>";s+="  <th>name</th>";s+="  <th>type</th>";s+="  <th>info</th>";s+="</tr>";for(let e=0;e<y.json.cameras.length;e++){s+="<tr>";s+="<td>"+y.json.cameras[e].name+"</td>";s+="<td>"+y.json.cameras[e].type+"</td>";s+="<td>";if(y.json.cameras[e].perspective){s+="yfov: "+Math.round(y.json.cameras[e].perspective.yfov*100)/100;s+=", ";s+="zfar: "+Math.round(y.json.cameras[e].perspective.zfar*100)/100;s+=", ";s+="znear: "+Math.round(y.json.cameras[e].perspective.znear*100)/100}s+="</td>";s+="<tr>"}s+="</table>"}let f=0;if(y.json.skins)f=y.json.skins.length;s+='<div id="groupSkins">Skins ('+f+")</div>";if(y.json.skins){s+='<table id="sectionSkins" class="table treetable">';s+="<tr>";s+="  <th>name</th>";s+="  <th></th>";s+="  <th>total joints</th>";s+="</tr>";for(let e=0;e<y.json.skins.length;e++){s+="<tr>";s+="<td>"+y.json.skins[e].name+"</td>";s+="<td>"+"</td>";s+="<td>"+y.json.skins[e].joints.length+"</td>";s+="<td>";s+="</td>";s+="<tr>"}s+="</table>"}if(y.timing){s+='<div id="groupTiming">Debug Loading Timing </div>';s+='<table id="sectionTiming" class="table treetable">';s+="<tr>";s+="  <th>task</th>";s+="  <th>time used</th>";s+="</tr>";let e=0;for(let e=0;e<y.timing.length-1;e++){s+="<tr>";s+="  <td>"+y.timing[e][0]+"</td>";s+="  <td>"+(y.timing[e+1][1]-y.timing[e][1])+" ms</td>";s+="</tr>"}s+="</table>"}let c=0;if(y.json.buffers)c=y.json.buffers[0].byteLength;s+='<div id="groupBinary">File Size Allocation ('+Math.round(c/1024)+"k )</div>";s+='<table id="sectionBinary" class="table treetable">';s+="<tr>";s+="  <th>name</th>";s+="  <th>size</th>";s+="  <th>%</th>";s+="</tr>";let d=c;for(let e in r){s+="<tr>";s+="<td>"+e+"</td>";s+="<td>"+Y(r[e])+" </td>";s+="<td>"+Math.round(r[e]/c*100)+"% </td>";s+="<tr>";d-=r[e]}if(d!=0){s+="<tr>";s+="<td>unknown</td>";s+="<td>"+Y(d)+" </td>";s+="<td>"+Math.round(d/c*100)+"% </td>";s+="<tr>"}s+="</table>";s+="</div>";C=new CABLES.UI.Tab("GLTF "+CABLES.basename(B.get()),{icon:"cube",infotext:"tab_gltf",padding:true,singleton:true});gui.mainTabs.addTab(C,true);C.addEventListener("close",b);C.html(s);CABLES.UI.Collapsable.setup(ele.byId("groupNodes"),ele.byId("sectionNodes"),false);CABLES.UI.Collapsable.setup(ele.byId("groupMaterials"),ele.byId("materialtable"),true);CABLES.UI.Collapsable.setup(ele.byId("groupAnims"),ele.byId("sectionAnim"),true);CABLES.UI.Collapsable.setup(ele.byId("groupMeshes"),ele.byId("meshestable"),true);CABLES.UI.Collapsable.setup(ele.byId("groupCameras"),ele.byId("sectionCameras"),true);CABLES.UI.Collapsable.setup(ele.byId("groupImages"),ele.byId("sectionImages"),true);CABLES.UI.Collapsable.setup(ele.byId("groupSkins"),ele.byId("sectionSkins"),true);CABLES.UI.Collapsable.setup(ele.byId("groupBinary"),ele.byId("sectionBinary"),true);CABLES.UI.Collapsable.setup(ele.byId("groupTiming"),ele.byId("sectionTiming"),true);gui.maintabPanel.show(true)}function Y(e){if(e>1024)return Math.round(e/1024)+" kb";if(e>1024*500)return Math.round(e/1024)+" mb";else return e+" bytes"}const Z=class{constructor(e){this._mod=null;this._node=e;this._lastTime=0;this._matArr=[];this._m=mat4.create();this._invBindMatrix=mat4.create();this.identity=true}renderFinish(e){e.popModelMatrix();this._mod.unbind()}renderStart(e,t){if(!this._mod){this._mod=new CGL.ShaderModifier(e,_.name+this._node.name);this._mod.addModule({priority:-2,name:"MODULE_VERTEX_POSITION",srcHeadVert:l.skin_head_vert||"",srcBodyVert:l.skin_vert||""});this._mod.addUniformVert("m4[]","MOD_boneMats",[]);const r=vec3.create()}const n=this._node.skin;const i=y.json.skins[n].joints.length*16;{if(this._matArr.length!=i)this._matArr.length=i;for(let e=0;e<y.json.skins[n].joints.length;e++){const s=e*16;const a=y.json.skins[n].joints[e];const o=y.nodes[a];for(let e=0;e<16;e++)this._invBindMatrix[e]=y.accBuffers[y.json.skins[n].inverseBindMatrices][s+e];mat4.mul(this._m,o.modelMatAbs(),this._invBindMatrix);for(let e=0;e<this._m.length;e++)this._matArr[s+e]=this._m[e]}this._mod.setUniformValue("MOD_boneMats",this._matArr);this._lastTime=t}this._mod.define("SKIN_NUM_BONES",y.json.skins[n].joints.length);this._mod.bind();e.pushModelMatrix();if(this.identity)mat4.identity(e.mMatrix)}};const K=_.inTrigger("Render"),t=_.inString("data"),B=_.inUrl("glb File",[".glb"]),Q=_.inBool("Draw",true),n=_.inDropDown("Camera",["None"],"None"),q=_.inString("Animation",""),J=_.inTriggerButton("Show Structure"),r=_.inSwitch("Center",["None","XYZ","XZ"],"XYZ"),s=_.inBool("Rescale",true),a=_.inFloat("Rescale Size",2.5),h=_.inFloat("Time"),u=_.inBool("Sync to timeline",false),$=_.inBool("Loop",true),ee=_.inSwitch("Normals Format",["XYZ","X-ZY"],"XYZ"),te=_.inSwitch("Vertices Format",["XYZ","XZ-Y"],"XYZ"),f=_.inBool("Calc Normals",false),c=_.inObject("Materials"),ne=_.inArray("Hide Nodes"),ie=_.inBool("Use Material Properties",false),d=_.inBool("Active",true),re=_.outTrigger("Render Before"),m=_.outTrigger("Next"),se=_.outString("Generator"),ae=_.outNumber("GLTF Version"),oe=_.outArray("GLTF Extensions Used"),le=_.outNumber("Anim Length",0),he=_.outNumber("Anim Time",0),ue=_.outObject("Json"),fe=_.outArray("Anims"),ce=_.outArray("BoundingPoints"),de=_.outObject("Bounds"),me=_.outTrigger("Finished"),ge=_.outBool("Loading");_.setPortGroup("Timing",[h,u,$]);const D=true;const g=_.patch.cgl;B.onChange=te.onChange=f.onChange=ee.onChange=L;_.toWorkPortsNeedToBeLinked(K);let pe=0;let p=false;let F=null;let A=[];let y=null;let x=0;let S=0;let T=true;let Fe=null;let O=null;let I=null;const Ae=vec3.create();let Ce=0;let _e=false;const w=vec3.create();J.onTriggered=e;t.setUiAttribs({hideParam:true,hidePort:true});t.onChange=Se;ne.onChange=N;q.onChange=Oe;_.setPortGroup("Transform",[s,a,r]);r.onChange=ve;function Ee(){const t=["None"];if(y){for(let e=0;e<y.nodes.length;e++){if(y.nodes[e].camera>=0){t.push(y.nodes[e].name)}}}n.uiAttribs.values=t}function ve(){_e=r.get()!="None";if(y&&y.bounds){w.set(y.bounds.center);w[0]=-w[0];w[1]=-w[1];w[2]=-w[2];if(r.get()=="XZ")w[1]=-y.bounds.minY}}s.onChange=function(){a.setUiAttribs({greyout:!s.get()})};c.onChange=function(){T=true};_.onDelete=function(){b()};u.onChange=function(){h.setUiAttribs({greyout:u.get()})};n.onChange=be;function be(){F=null;if(!y)return;for(let e=0;e<y.nodes.length;e++){if(y.nodes[e].name==n.get())F=new i(y,y.nodes[e])}}K.onTriggered=function(){if(!p)return;if(!d.get())return;pe=0;if(u.get())S=_.patch.timer.getTime();else S=Math.max(0,h.get());if($.get()){S%=x;if(S<Ce)me.trigger()}else{if(x>0&&S>=x)me.trigger()}Ce=S;g.pushModelMatrix();he.set(S||0);if(p&&y&&y.bounds){if(s.get()){let e=a.get()/y.bounds.maxAxis;y.scale=e;vec3.set(Ae,e,e,e);mat4.scale(g.mMatrix,g.mMatrix,Ae)}if(_e){mat4.translate(g.mMatrix,g.mMatrix,w)}}let e=g.tempData.currentScene||null;g.tempData.currentScene=y;re.trigger();if(p){if(T)ye();if(F)F.start(S);if(y){y.time=S;{if(y.bounds&&g.shouldDrawHelpers(_)){if(CABLES.UI&&gui.shouldDrawOverlay)g.pushShader(CABLES.GL_MARKER.getDefaultShader(g));else g.pushShader(CABLES.GL_MARKER.getSelectedShader(g));y.bounds.render(g);g.popShader()}if(Q.get()){for(let e=0;e<y.nodes.length;e++)if(!y.nodes[e].isChild)y.nodes[e].render(g)}else{for(let e=0;e<y.nodes.length;e++)if(!y.nodes[e].isChild)y.nodes[e].render(g,false,true)}}}}m.trigger();g.tempData.currentScene=e;g.popModelMatrix();if(F)F.end()};function Be(){if(!y){_.setUiError("nogltf","gltf not found");return}_.setUiError("nogltf",null);if(y.loadingMeshes>0){setTimeout(Be,100);return}y.timing.push(["finishLoading()",Math.round(performance.now()-y.startTime)]);T=true;le.set(x);y.bounds=new CABLES.CG.BoundingBox;if(!y)_.setUiError("urlerror",'could not load gltf:<br/>"'+B.get()+'"',2);else _.setUiError("urlerror",null);y.timing.push(["start calc bounds",Math.round(performance.now()-y.startTime)]);for(let e=0;e<y.nodes.length;e++){const t=y.nodes[e];t.updateMatrix();if(!t.isChild)t.calcBounds(y,null,y.bounds)}if(y.bounds)de.set(y.bounds);y.timing.push(["calced bounds",Math.round(performance.now()-y.startTime)]);N();y.timing.push(["hideNodesFromData",Math.round(performance.now()-y.startTime)]);if(C)e();y.timing.push(["printinfo",Math.round(performance.now()-y.startTime)]);Ee();be();ce.set(A);if(y){if(B.get()&&!B.get().startsWith("data:")){_.setUiAttrib({extendTitle:CABLES.basename(B.get())})}y.loaded=Date.now()}if(y){for(let e=0;e<y.nodes.length;e++){if(!y.nodes[e].isChild){y.nodes[e].render(g,false,true,true,false,true,0)}}for(let e=0;e<y.nodes.length;e++){const t=y.nodes[e];t.children=we(t.children)}}ve();Oe();ge.set(false);g.patch.loading.finished(O);O=null;_.setUiAttrib({accBuffersDelete:CABLES.basename(B.get())});if(y.accBuffersDelete){for(let e=0;e<y.accBuffersDelete.length;e++){y.accBuffers[y.accBuffersDelete[e]]=null}}y.chunks=null;p=true}function De(e){if(!d.get())return;if(!O)O=g.patch.loading.start("gltfScene",B.get(),_);let t=B.get();let n=_.patch.getFilePath(String(B.get()));if(B.get()&&!B.get().startsWith("data:")){if(e===true)n+="?rnd="+CABLES.generateUUID()}p=false;ge.set(true);fetch(n).then(e=>{return e.arrayBuffer()}).then(e=>{if(B.get()!=t){g.patch.loading.finished(O);O=null;return}A=[];x=0;y=G(e);Be()}).catch(e=>{console.log(e)});b();const i=new XMLHttpRequest;i.open("GET",n,true);i.responseType="arraybuffer";g.patch.loading.addAssetLoadingTask(()=>{})}_.onFileChanged=function(e){if(B.get()&&B.get().indexOf(e)>-1){L(true)}};d.onChange=()=>{if(d.get())L();if(!d.get()){y=null}};function L(e){clearTimeout(Fe);Fe=setTimeout(function(){De(e)},30)}function ye(){if(!y)return;y.shaders={};if(c.links.length==1&&c.get()){const n=c.links[0].portOut.op;const i=n.getPort("Shader");const r=n.getPort("Material Name");if(!i&&!r){const s=c.get();for(let t in s){if(s[t]&&y.json.materials)for(let e=0;e<y.json.materials.length;e++){if(y.json.materials[e].name==t){if(y.shaders[e]){n.warn("double material assignment:",name)}y.shaders[e]=s[t]}}}}}if(c.get()){for(let e=0;e<c.links.length;e++){const t=c.links[e].portOut.op;const i=t.getPort("Shader");const r=t.getPort("Material Name");if(i&&r&&i.get()){const name=r.get();if(y.json.materials)for(let e=0;e<y.json.materials.length;e++)if(y.json.materials[e].name==name){if(y.shaders[e]){t.warn("double material assignment:",name)}y.shaders[e]=i.get()}}}}T=false;if(C)e()}function xe(){const t=ne.get();if(!y||!I||!I.hiddenNodes)return;if(!t){return}for(let e=0;e<t.length;e++){const n=y.getNode(t[e]);if(n)n.hidden=true}}function N(){if(!I)Se();if(!y)return;y.unHideAll();if(I&&I.hiddenNodes){for(const e in I.hiddenNodes){const t=y.getNode(e);if(t)t.hidden=true;else _.verbose("node to be hidden not found",e,t)}}xe()}function Se(){I=t.get();if(!I||I==="")I={};else I=JSON.parse(I);if(y)N();return I}function Te(){t.set(JSON.stringify(I))}function Oe(){if(y&&y.nodes){for(let e=0;e<y.nodes.length;e++){y.nodes[e].setAnimAction(q.get())}}}function Ie(t,n){for(let e=0;e<y.nodes.length;e++){if(y.nodes[e].children.indexOf(n)>=0){t.push(y.nodes[e]);if(y.nodes[e].isChild)Ie(t,e)}}}_.exposeTexture=function(e){const t=gui.corePatch().addOp("Ops.Gl.GLTF.GltfTexture");t.getPort("Name").set(e);R(t,1);_.patch.link(_,m.name,t,"Render");gui.patchView.testCollision(t);gui.patchView.centerSelectOp(t.id,true)};_.exposeGeom=function(e,t){const n=gui.corePatch().addOp("Ops.Gl.GLTF.GltfGeometry");n.getPort("Name").set(e);n.getPort("Submesh").set(t);R(n,1);_.patch.link(_,m.name,n,"Update");gui.patchView.testCollision(n);gui.patchView.centerSelectOp(n.id,true)};function R(e,t){t=t||1;e.setUiAttrib({subPatch:_.uiAttribs.subPatch,translate:{x:_.uiAttribs.translate.x,y:_.uiAttribs.translate.y+t*CABLES.GLUI.glUiConfig.newOpDistanceY}})}_.exposeNode=function(n,e,i){let t=e=="hierarchy";if(t){let r=[];for(let e=0;e<y.nodes.length;e++){if(y.nodes[e].name==n){let t=[];const s=y.nodes[e];Ie(t,e);t=t.reverse();t.push(s,s);let n=m.name;let i=_;for(let e=0;e<t.length;e++){const a=gui.corePatch().addOp("Ops.Gl.GLTF.GltfNode_v2");a.getPort("Node Name").set(t[e].name);_.patch.link(i,n,a,"Render");R(a,e);if(e==t.length-1){a.getPort("Transformation").set(false)}else{a.getPort("Draw Mesh").set(false);a.getPort("Draw Childs").set(false)}n="Next";i=a;r.push(a);gui.patchView.testCollision(a)}}}for(let e=0;e<r.length;e++){r[e].selectChilds()}}else{let t="Ops.Gl.GLTF.GltfNode_v2";if(i&&i.skin)t="Ops.Gl.GLTF.GltfSkin";if(e=="transform")t="Ops.Gl.GLTF.GltfNodeTransform_v2";gui.serverOps.loadOpLibs(t,()=>{let e=gui.corePatch().addOp(t);e.getPort("Node Name").set(n);R(e);_.patch.link(_,m.name,e,"Render");gui.patchView.testCollision(e);gui.patchView.centerSelectOp(e.id,true)})}gui.closeModal()};_.assignMaterial=function(e){const t=gui.corePatch().addOp("Ops.Gl.GLTF.GltfSetMaterial");t.getPort("Material Name").set(e);_.patch.link(_,c.name,t,"Material");R(t);gui.patchView.testCollision(t);gui.patchView.centerSelectOp(t.id,true);gui.closeModal()};_.toggleNodeVisibility=function(e){const t=y.getNode(e);t.hidden=!t.hidden;I.hiddenNodes=I.hiddenNodes||{};if(t)if(t.hidden)I.hiddenNodes[e]=true;else delete I.hiddenNodes[e];Te()};function we(n){const i={},r=[];for(let e=0,t=n.length;e<t;++e){if(!i.hasOwnProperty(n[e])){r.push(n[e]);i[n[e]]=1}}return r}};Ops.Gl.GLTF.GltfScene_v3.prototype=new CABLES.Op;CABLES.OPS["a9c59d94-8aea-4c20-ab5d-63ce46ecfa16"]={f:Ops.Gl.GLTF.GltfScene_v3,objName:"Ops.Gl.GLTF.GltfScene_v3"};Ops.Gl.Shader.MatCapMaterial_v3=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={matcap_frag:"{{MODULES_HEAD}}\n\n#ifdef HAS_TEXTURES\n    IN vec2 texCoord;\n#endif\n\nIN vec3 transformedNormal;\nIN vec3 viewSpacePosition;\n\nUNI vec4 inColor;\n\nUNI sampler2D texMatcap;\n\n#ifdef HAS_DIFFUSE_TEXTURE\n   UNI sampler2D texDiffuse;\n#endif\n\n#ifdef USE_SPECULAR_TEXTURE\n   UNI sampler2D texSpec;\n   UNI sampler2D texSpecMatCap;\n#endif\n\n#ifdef HAS_AO_TEXTURE\n    UNI sampler2D texAo;\n    UNI float aoIntensity;\n#endif\n\n#ifdef HAS_NORMAL_TEXTURE\n    IN vec3 vBiTangent;\n    IN vec3 vTangent;\n    IN mat3 normalMatrix;\n\n    UNI sampler2D texNormal;\n    UNI float normalMapIntensity;\n#endif\n\n#ifdef HAS_TEXTURE_OPACITY\n    UNI sampler2D texOpacity;\n#endif\n\n#ifdef CALC_SSNORMALS\n    IN vec3 eye_relative_pos;\n\n    // from https://www.enkisoftware.com/devlogpost-20150131-1-Normal_generation_in_the_pixel_shader\n    vec3 CalculateScreenSpaceNormals() {\n    \tvec3 dFdxPos = dFdx(eye_relative_pos);\n    \tvec3 dFdyPos = dFdy(eye_relative_pos);\n    \tvec3 screenSpaceNormal = normalize( cross(dFdxPos, dFdyPos));\n        return normalize(screenSpaceNormal);\n    }\n#endif\n\n// * taken & modified from https://github.com/mrdoob/three.js/blob/dev/src/renderers/shaders/ShaderLib/meshmatcap_frag.glsl.js\nvec2 getMatCapUV(vec3 viewSpacePosition, vec3 normal) {\n    vec3 viewDir = normalize(-viewSpacePosition);\n\tvec3 x = normalize(vec3(viewDir.z, 0.0, - viewDir.x));\n\tvec3 y = normalize(cross(viewDir, x));\n\tvec2 uv = vec2(dot(x, normal), dot(y, normal)) * 0.495 + 0.5; // 0.495 to remove artifacts caused by undersized matcap disks\n\treturn uv;\n}\n\nvoid main()\n{\n    vec3 viewSpaceNormal = normalize(transformedNormal);\n\n\n\n    #ifdef HAS_TEXTURES\n        vec2 texCoords = texCoord;\n        {{MODULE_BEGIN_FRAG}}\n    #endif\n\n\n\n    #ifdef DOUBLE_SIDED\n        if(!gl_FrontFacing) viewSpaceNormal *= -1.0;\n    #endif\n\n    #ifdef CALC_SSNORMALS\n        viewSpaceNormal = CalculateScreenSpaceNormals();\n    #endif\n\n\n\n   #ifdef HAS_NORMAL_TEXTURE\n        vec3 normalFromMap = texture( texNormal, texCoord ).xyz * 2.0 - 1.0;\n        normalFromMap = normalize(normalFromMap);\n\n        vec3 tangent;\n        vec3 binormal;\n\n        #ifdef CALC_TANGENT\n            vec3 c1 = cross(normalFromMap, vec3(0.0, 0.0, 1.0));\n            vec3 c2 = cross(normalFromMap, vec3(0.0, 1.0, 0.0));\n\n            tangent = c1;\n            tangent = normalize(tangent);\n            binormal = cross(viewSpaceNormal, tangent);\n            binormal = normalize(binormal);\n        #endif\n\n        #ifndef CALC_TANGENT\n            tangent = normalize(normalMatrix * vTangent);\n            vec3 bitangent = normalize(normalMatrix * vBiTangent);\n            binormal = normalize(cross(viewSpaceNormal, bitangent));\n        #endif\n\n        normalFromMap = normalize(\n            tangent * normalFromMap.x\n            + binormal * normalFromMap.y\n            + viewSpaceNormal * normalFromMap.z\n        );\n\n        vec3 mixedNormal = normalize(viewSpaceNormal + normalFromMap * normalMapIntensity);\n\n        viewSpaceNormal = mixedNormal;\n    #endif\n\n    vec4 col = texture(texMatcap, getMatCapUV(viewSpacePosition, viewSpaceNormal));\n\n    #ifdef HAS_DIFFUSE_TEXTURE\n        col = col*texture(texDiffuse, texCoords);\n    #endif\n\n    col.rgb *= inColor.rgb;\n\n\n    #ifdef HAS_AO_TEXTURE\n        col = col\n            * mix(\n                vec4(1.0,1.0,1.0,1.0),\n                texture(texAo, texCoords),\n                aoIntensity\n            );\n    #endif\n\n    #ifdef USE_SPECULAR_TEXTURE\n        vec4 spec = texture(texSpecMatCap, getMatCapUV(viewSpacePosition, viewSpaceNormal));\n        spec *= texture(texSpec, texCoords);\n        col += spec;\n    #endif\n\n    col.a *= inColor.a;\n\n    #ifdef HAS_TEXTURE_OPACITY\n        #ifdef TRANSFORMALPHATEXCOORDS\n            texCoords=vec2(texCoord.s,1.0-texCoord.t);\n            texCoords.y = 1. - texCoords.y;\n        #endif\n        #ifdef ALPHA_MASK_ALPHA\n            col.a*=texture(texOpacity,texCoords).a;\n        #endif\n        #ifdef ALPHA_MASK_LUMI\n            col.a*=dot(vec3(0.2126,0.7152,0.0722), texture(texOpacity,texCoords).rgb);\n        #endif\n        #ifdef ALPHA_MASK_R\n            col.a*=texture(texOpacity,texCoords).r;\n        #endif\n        #ifdef ALPHA_MASK_G\n            col.a*=texture(texOpacity,texCoords).g;\n        #endif\n        #ifdef ALPHA_MASK_B\n            col.a*=texture(texOpacity,texCoords).b;\n        #endif\n\n        #ifdef DISCARDTRANS\n            if(col.a < 0.2) discard;\n        #endif\n    #endif\n\n    {{MODULE_COLOR}}\n\n    outColor = col;\n}",matcap_vert:"IN vec3 vPosition;\n\n#ifdef HAS_TEXTURES\n    IN vec2 attrTexCoord;\n#endif\n\nIN vec3 attrVertNormal;\nIN float attrVertIndex;\n\n#ifdef HAS_NORMAL_TEXTURE\n    IN vec3 attrTangent;\n    IN vec3 attrBiTangent;\n    OUT vec3 vBiTangent;\n    OUT vec3 vTangent;\n#endif\n\nUNI mat4 projMatrix;\nUNI mat4 modelMatrix;\nUNI mat4 viewMatrix;\nUNI vec3 camPos;\n\n#ifdef HAS_TEXTURES\n    UNI vec2 texOffset;\n    UNI vec2 texRepeat;\n    OUT vec2 texCoord;\n#endif\n\nOUT mat3 normalMatrix;\nOUT vec3 viewSpacePosition;\nOUT vec3 transformedNormal;\n\n{{MODULES_HEAD}}\n\n#ifdef CALC_SSNORMALS\n    // from https://www.enkisoftware.com/devlogpost-20150131-1-Normal_generation_in_the_pixel_shader\n    OUT vec3 eye_relative_pos;\n#endif\n\nmat3 transposeMat3(mat3 m) {\n    return mat3(m[0][0], m[1][0], m[2][0],\n        m[0][1], m[1][1], m[2][1],\n        m[0][2], m[1][2], m[2][2]);\n}\n\n mat3 inverseMat3(mat3 m) {\n    float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2];\n    float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2];\n    float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2];\n\n    float b01 = a22 * a11 - a12 * a21;\n    float b11 = -a22 * a10 + a12 * a20;\n    float b21 = a21 * a10 - a11 * a20;\n\n    float det = a00 * b01 + a01 * b11 + a02 * b21;\n\n    return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11),\n        b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10),\n        b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det;\n}\n\nvoid main()\n{\n    #ifdef HAS_TEXTURES\n        texCoord = texRepeat * vec2(attrTexCoord.x, attrTexCoord.y) + texOffset;\n        texCoord.y = 1. - texCoord.y;\n    #endif\n\n    mat4 mMatrix = modelMatrix;\n    mat4 mvMatrix;\n\n    #ifdef HAS_NORMAL_TEXTURE\n        vec3 tangent = attrTangent;\n        vec3 bitangent = attrBiTangent;\n        vTangent = attrTangent;\n        vBiTangent = attrBiTangent;\n    #endif\n\n    vec4 pos = vec4(vPosition, 1.);\n    vec3 norm = attrVertNormal;\n\n    {{MODULE_VERTEX_POSITION}}\n\n    mvMatrix = viewMatrix * mMatrix;\n    vec3 normal = norm;\n\n    normalMatrix = transposeMat3(inverseMat3(mat3(mvMatrix)));\n\n    vec3 fragPos = vec3((mvMatrix) * pos);\n    viewSpacePosition = normalize(fragPos);\n\n    #ifdef CALC_SSNORMALS\n        eye_relative_pos = -(vec3(viewMatrix * vec4(camPos, 1.)) - fragPos);\n    #endif\n\n    transformedNormal = normalize(mat3(normalMatrix) * normal);\n\n    mat4 modelViewMatrix=mvMatrix;\n    {{MODULE_VERTEX_MODELVIEW}}\n\n    gl_Position = projMatrix * modelViewMatrix * pos;\n\n}\n"};const n=e.patch.cgl;const k=e.inTrigger("Render"),i=e.inTexture("MatCap"),r=e.inTexture("Diffuse"),s=e.inTexture("Normal"),a=e.inTexture("Specular Mask"),o=e.inTexture("Specular MatCap"),l=e.inTexture("AO Texture"),h=e.inTexture("Opacity Texture"),u=e.inValueSlider("r",1),f=e.inValueSlider("g",1),c=e.inValueSlider("b",1),d=e.inValueSlider("Opacity",1),m=e.inValueSlider("AO Intensity",1),g=e.inFloatSlider("Normal Map Intensity",1),p=e.inValue("Repeat X",1),F=e.inValue("Repeat Y",1),A=e.inValue("Offset X",0),C=e.inValue("Offset Y",0),_=e.inValueBool("Double Sided"),E=e.inValueBool("Screen Space Normals"),v=e.inValueBool("Calc normal tangents",true),b=e.inValueBool("Opacity TexCoords Transform",false),B=e.inValueBool("Discard Transparent Pixels"),M=e.outTrigger("Next"),P=e.outObject("Shader");u.setUiAttribs({colorPick:true});const D=e.inSwitch("Alpha Mask Source",["Luminance","R","G","B","A"],"Luminance");D.setUiAttribs({greyout:true});e.setPortGroup("Normals",[v,E,_]);e.setPortGroup("Texture Opacity",[D,b,B]);e.setPortGroup("Texture Transforms",[m,g,p,F,A,C]);e.setPortGroup("Texture Maps",[r,s,a,o,l,h]);e.setPortGroup("Color",[u,f,c,d]);const y=new CGL.Shader(n,"MatCapMaterialNew3");const U=new CGL.Uniform(y,"f","opacity",d);y.setModules(["MODULE_VERTEX_POSITION","MODULE_COLOR","MODULE_BEGIN_FRAG","MODULE_VERTEX_MODELVIEW"]);y.setSource(t.matcap_vert,t.matcap_frag);P.set(y);const V=new CGL.Uniform(y,"t","texMatcap");let x=null;let S=null;let T=null;let O=null;let I=null;let w=null;const G=new CGL.Uniform(y,"2f","texOffset",A,C);const j=new CGL.Uniform(y,"2f","texRepeat",p,F);const z=new CGL.Uniform(y,"f","aoIntensity",m);const X=new CGL.Uniform(y,"4f","inColor",u,f,c,d);_.onChange=v.onChange=L;L();function L(){y.toggleDefine("DOUBLE_SIDED",_.get());if(v.get())y.define("CALC_TANGENT");else y.removeDefine("CALC_TANGENT")}E.onChange=function(){if(E.get()){if(n.glVersion<2){n.gl.getExtension("OES_standard_derivatives");y.enableExtension("GL_OES_standard_derivatives")}y.define("CALC_SSNORMALS")}else y.removeDefine("CALC_SSNORMALS")};i.onChange=N;function N(){if(!n.defaultMatcapTex3){const i=new Uint8Array(256*4);for(let n=0;n<16;n++){for(let t=0;t<16;t++){let e=t*16;e*=Math.min(1,(n+t/3)/8);i[(n+t*16)*4+0]=i[(n+t*16)*4+1]=i[(n+t*16)*4+2]=e;i[(n+t*16)*4+3]=255}}n.defaultMatcapTex3=new CGL.Texture(n);n.defaultMatcapTex3.initFromData(i,16,16,CGL.Texture.FILTER_LINEAR,CGL.Texture.WRAP_REPEAT)}}r.onChange=function(){if(r.get()){if(x!==null)return;y.define("HAS_DIFFUSE_TEXTURE");y.removeUniform("texDiffuse");x=new CGL.Uniform(y,"t","texDiffuse")}else{y.removeDefine("HAS_DIFFUSE_TEXTURE");y.removeUniform("texDiffuse");x=null}};s.onChange=function(){if(s.get()){if(S!==null)return;y.define("HAS_NORMAL_TEXTURE");y.removeUniform("texNormal");S=new CGL.Uniform(y,"t","texNormal");if(!T)T=new CGL.Uniform(y,"f","normalMapIntensity",g)}else{y.removeDefine("HAS_NORMAL_TEXTURE");y.removeUniform("texNormal");S=null}};l.onChange=function(){if(l.get()){if(w!==null)return;y.define("HAS_AO_TEXTURE");y.removeUniform("texAo");w=new CGL.Uniform(y,"t","texAo")}else{y.removeDefine("HAS_AO_TEXTURE");y.removeUniform("texAo");w=null}};a.onChange=o.onChange=function(){if(a.get()&&o.get()){if(O!==null)return;y.define("USE_SPECULAR_TEXTURE");y.removeUniform("texSpec");y.removeUniform("texSpecMatCap");O=new CGL.Uniform(y,"t","texSpec");I=new CGL.Uniform(y,"t","texSpecMatCap")}else{y.removeDefine("USE_SPECULAR_TEXTURE");y.removeUniform("texSpec");y.removeUniform("texSpecMatCap");O=null;I=null}};function H(){if(D.get()=="Alpha Channel")y.define("ALPHA_MASK_ALPHA");else y.removeDefine("ALPHA_MASK_ALPHA");if(D.get()=="Luminance")y.define("ALPHA_MASK_LUMI");else y.removeDefine("ALPHA_MASK_LUMI");if(D.get()=="R")y.define("ALPHA_MASK_R");else y.removeDefine("ALPHA_MASK_R");if(D.get()=="G")y.define("ALPHA_MASK_G");else y.removeDefine("ALPHA_MASK_G");if(D.get()=="B")y.define("ALPHA_MASK_B");else y.removeDefine("ALPHA_MASK_B")}D.onChange=H;h.onChange=W;let R=null;function W(){if(h.get()){if(R!==null)return;y.removeUniform("texOpacity");y.define("HAS_TEXTURE_OPACITY");if(!R)R=new CGL.Uniform(y,"t","texOpacity");D.setUiAttribs({greyout:false});B.setUiAttribs({greyout:false});b.setUiAttribs({greyout:false})}else{y.removeUniform("texOpacity");y.removeDefine("HAS_TEXTURE_OPACITY");R=null;D.setUiAttribs({greyout:true});B.setUiAttribs({greyout:true});b.setUiAttribs({greyout:true})}H()}B.onChange=function(){if(B.get())y.define("DISCARDTRANS");else y.removeDefine("DISCARDTRANS")};b.onChange=function(){if(b.get())y.define("TRANSFORMALPHATEXCOORDS");else y.removeDefine("TRANSFORMALPHATEXCOORDS")};function Y(){if(a.get()&&!o.get()){e.setUiError("specNoMatCapSpec","You connected a specular texture but have not connected a specular matcap texture. You need to connect both texture inputs for the specular input to work.",1);e.setUiError("noSpecMatCapSpec",null)}else if(!a.get()&&o.get()){e.setUiError("noSpecMatCapSpec","You connected a specular matcap texture but have not connected a specular texture. You need to connect both texture inputs for the specular input to work.",1);e.setUiError("specNoMatCapSpec",null)}else if(a.get()&&o.get()){e.setUiError("specNoMatCapSpec",null);e.setUiError("noSpecMatCapSpec",null)}else{e.setUiError("specNoMatCapSpec",null);e.setUiError("noSpecMatCapSpec",null)}}k.onTriggered=function(){Y();if(!n.defaultMatcapTex3)N();y.popTextures();const e=i.get()||n.defaultMatcapTex3;y.pushTexture(V,e.tex);if(r.get()&&x)y.pushTexture(x,r.get().tex);if(s.get()&&S)y.pushTexture(S,s.get().tex);if(a.get()&&O)y.pushTexture(O,a.get().tex);if(o.get()&&I)y.pushTexture(I,o.get().tex);if(l.get()&&w)y.pushTexture(w,l.get().tex);if(h.get()&&R)y.pushTexture(R,h.get().tex);n.pushShader(y);M.trigger();n.popShader()}};Ops.Gl.Shader.MatCapMaterial_v3.prototype=new CABLES.Op;CABLES.OPS["c1dd6e76-61b4-471a-b8d1-f550a5a9a4f4"]={f:Ops.Gl.Shader.MatCapMaterial_v3,objName:"Ops.Gl.Shader.MatCapMaterial_v3"};Ops.Gl.Texture_v2=function(){CABLES.Op.apply(this,arguments);const r=this;const e=r.attachments={};const s=r.inUrl("File",[".jpg",".png",".webp",".jpeg",".avif"]),t=r.inSwitch("Filter",["nearest","linear","mipmap"]),n=r.inValueSelect("Wrap",["repeat","mirrored repeat","clamp to edge"],"clamp to edge"),i=r.inSwitch("Anisotropic",["0","1","2","4","8","16"],"0"),a=r.inSwitch("Data Format",["R","RG","RGB","RGBA","SRGBA"],"RGBA"),o=r.inValueBool("Flip",false),l=r.inValueBool("Pre Multiplied Alpha",false),h=r.inValueBool("Active",true),u=r.inBool("Save Memory",true),f=r.outTexture("Texture"),c=r.inBool("Add Cachebuster",false),d=r.inTriggerButton("Reload"),m=r.outNumber("Width"),g=r.outNumber("Height"),p=r.outNumber("Aspect Ratio"),F=r.outBoolNum("Loaded",0),A=r.outBoolNum("Loading",0);const C=r.patch.cgl;r.toWorkPortsNeedToBeLinked(f);r.setPortGroup("Size",[m,g]);let _=null;let E=null;let v=null;let b=CGL.Texture.FILTER_MIPMAP;let B=CGL.Texture.WRAP_REPEAT;let D=0;let y=0;l.setUiAttribs({hidePort:true});l.onChange=s.onChange=a.onChange=c.onChange=o.onChange=S;i.onChange=t.onChange=I;n.onChange=w;t.set("mipmap");n.set("repeat");f.setRef(CGL.Texture.getEmptyTexture(C));d.onTriggered=S;h.onChange=function(){if(h.get()){if(_!=s.get()||!v)S();else f.setRef(v)}else{f.setRef(CGL.Texture.getEmptyTexture(C));m.set(CGL.Texture.getEmptyTexture(C).width);g.set(CGL.Texture.getEmptyTexture(C).height);if(v)v.delete();r.setUiAttrib({extendTitle:""});v=null}};const x=function(){const e=CGL.Texture.getTempTexture(C);f.setRef(e)};function S(e){clearTimeout(y);y=setTimeout(function(){O(e)},1)}function T(){if(a.get()=="R")return CGL.Texture.PFORMATSTR_R8UB;if(a.get()=="RG")return CGL.Texture.PFORMATSTR_RG8UB;if(a.get()=="RGB")return CGL.Texture.PFORMATSTR_RGB8UB;if(a.get()=="SRGBA")return CGL.Texture.PFORMATSTR_SRGBA8;return CGL.Texture.PFORMATSTR_RGBA8UB}function O(e){r.checkMainloopExists();if(!h.get())return;if(E)E=C.patch.loading.finished(E);E=C.patch.loading.start(r.objName,s.get(),r);let t=r.patch.getFilePath(String(s.get()));if(c.get()||e===true)t=CABLES.cacheBust(t);if(String(s.get()).indexOf("data:")==0)t=s.get();let n=false;_=s.get();if(s.get()&&s.get().length>1){F.set(false);A.set(true);const i=s.get();r.setUiAttrib({extendTitle:CABLES.basename(t)});if(n)r.refreshParams();C.patch.loading.addAssetLoadingTask(()=>{r.setUiError("urlerror",null);CGL.Texture.load(C,t,function(e,t){C.checkFrameStarted("texture inittexture");if(s.get()!=i){E=C.patch.loading.finished(E);return}if(v)v.delete();if(e){const n=CGL.Texture.getErrorTexture(C);f.setRef(n);r.setUiError("urlerror",'could not load texture: "'+s.get()+'"',2);E=C.patch.loading.finished(E);return}m.set(t.width);g.set(t.height);p.set(t.width/t.height);v=t;f.setRef(v);A.set(false);F.set(true);if(u.get())v.image=null;if(E){E=C.patch.loading.finished(E)}r.checkMainloopExists()},{anisotropic:D,wrap:B,flip:o.get(),unpackAlpha:l.get(),pixelFormat:T(),filter:b});r.checkMainloopExists()})}else{x();E=C.patch.loading.finished(E)}}function I(){if(t.get()=="nearest")b=CGL.Texture.FILTER_NEAREST;else if(t.get()=="linear")b=CGL.Texture.FILTER_LINEAR;else if(t.get()=="mipmap")b=CGL.Texture.FILTER_MIPMAP;else if(t.get()=="Anisotropic")b=CGL.Texture.FILTER_ANISOTROPIC;i.setUiAttribs({greyout:b!=CGL.Texture.FILTER_MIPMAP});D=parseFloat(i.get());S()}function w(){if(n.get()=="repeat")B=CGL.Texture.WRAP_REPEAT;if(n.get()=="mirrored repeat")B=CGL.Texture.WRAP_MIRRORED_REPEAT;if(n.get()=="clamp to edge")B=CGL.Texture.WRAP_CLAMP_TO_EDGE;S()}r.onFileChanged=function(e){if(s.get()&&s.get().indexOf(e)>-1){f.setRef(CGL.Texture.getEmptyTexture(r.patch.cgl));f.setRef(CGL.Texture.getTempTexture(C));O(true)}}};Ops.Gl.Texture_v2.prototype=new CABLES.Op;CABLES.OPS["790f3702-9833-464e-8e37-6f0f813f7e16"]={f:Ops.Gl.Texture_v2,objName:"Ops.Gl.Texture_v2"};Ops.Number.Integer=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.inInt("Integer",0),i=e.outNumber("Number out");n.onChange=function(){i.set(Math.floor(n.get()))}};Ops.Number.Integer.prototype=new CABLES.Op;CABLES.OPS["17bc01d7-04ad-4aab-b88b-bb09744c4a69"]={f:Ops.Number.Integer,objName:"Ops.Number.Integer"};Ops.Gl.RenderAnim_v2=function(){CABLES.Op.apply(this,arguments);const o=this;const R=o.attachments={};const e=o.inTrigger("Render"),l=o.outTrigger("Next"),h=o.inDropDown("File Type",["PNG","JPG","WebP","WebM"],"PNG"),t=o.inBool("ZIP multiple files",false),u=o.inBool("Download Files",true),n=o.inString("Filename","cables"),f=o.inFloatSlider("Quality",.8),i=o.inSwitch("Duration Type",["Seconds","Frames"],"Seconds"),r=o.inInt("Duration",1),s=o.inInt("FPS",30),c=o.inValueBool("Transparency",false),d=o.inValueBool("Use Canvas Size",true),a=o.inValueInt("texture width",512),m=o.inValueInt("texture height",512),k=o.inTriggerButton("Start"),M=o.outNumber("Progress",0),P=o.outNumber("Frame",0),g=o.outString("Status","Waiting"),U=o.outBool("Started"),p=o.outString("Data URL"),F=o.outTrigger("Finished");o.setPortGroup("File",[h,t,u,n,f]);o.setPortGroup("Size",[d,a,m]);o.setPortGroup("Timing",[s,i,r]);p.ignoreValueSerialize=true;e.onTriggered=z;let A=false;let C=0;const V=true;let _=30;let E=31;const G=false;let v=CABLES.shortId();let j=false;const b=[];let B=-1;let D=0;let y="";let x=null;let S=o.patch.cgl.canvasWidth;let T=o.patch.cgl.canvasHeight;h.onChange=O;d.onChange=I;O();I();t.onChange=()=>{x=null};function O(){f.setUiAttribs({greyout:h.get()=="PNG"})}function I(){a.setUiAttribs({greyout:d.get()});m.setUiAttribs({greyout:d.get()})}k.onTriggered=function(){y=n.get();o.log("pref",y);b.length=0;g.set("Starting");_=s.get();E=r.get()*_;if(i.get()=="Frames")E=r.get();v=CABLES.shortId();w();if(t.get())x=new JSZip;if(!d.get()){S=CABLES.patch.cgl.canvasWidth;T=CABLES.patch.cgl.canvasHeight;o.patch.cgl.setSize(a.get()/CABLES.patch.cgl.pixelDensity,m.get()/CABLES.patch.cgl.pixelDensity);o.patch.cgl.updateSize()}if(E==0){C=0;A=true}else{C=-20;A=true;B=-9999}};function w(){if(E>=0){D=Math.max(0,C*(1/_));o.patch.timer.setTime(D);CABLES.overwriteTime=D;o.patch.freeTimer.setTime(D)}}function L(){A=false;CABLES.overwriteTime=undefined;g.set("Finished")}function z(){U.set(A);if(!A){l.trigger();return}const e=CABLES.internalNow;if(A){CABLES.internalNow=function(){return D*1e3};w()}if(B==C){l.trigger();return}B=C;let t=C/E;if(t<0)t=0;M.set(t);P.set(C);l.trigger();CABLES.internalNow=e;j=false;if(C>E){o.log("FINISHED...");o.log("ffmpeg -y -framerate 30 -f image2 -i "+y+"_%d.png  -b 9999k -vcodec mpeg4 "+v+".mp4");if(!d.get()){o.patch.cgl.setSize(S,T);o.patch.cgl.updateSize()}if(x){x.generateAsync({type:"blob"}).then(function(e){const t=document.createElement("a");t.download=y+".zip";t.href=URL.createObjectURL(e);if(u.get()){t.click()}L();if(p.isLinked()){N(e,e=>{p.set(e);F.trigger()})}else{p.set(null);F.trigger()}})}else if(h.get()=="WebM"){try{g.set("Creating Video File from frames");o.log("webm frames",b.length);const r=Whammy.fromImageArray(b,_);const s=window.URL.createObjectURL(r);const a=document.createElement("a");a.setAttribute("download",y+".webm");a.setAttribute("href",s);document.body.appendChild(a);if(u.get()){a.click()}L();if(p.isLinked()){N(r,e=>{p.set(e);F.trigger()})}else{p.set(null);F.trigger()}}catch(e){o.logError(e)}b.length=0}else L();return}let n="image/png";let i="png";if(h.get()=="JPG"){n="image/jpeg";i="jpg"}else if(h.get()=="WebP"){n="image/webp";i="webp"}if(C>0){g.set("Rendering Frame "+C+" of "+E);o.log("Rendering Frame "+C+" of "+E,D);if(h.get()=="WebM"){b.push(o.patch.cgl.canvas.toDataURL("image/webp",f.get()*.999));C++;w()}else{o.log("screenshotting frame...",C);o.patch.cgl.screenShot(n=>{if(n){if(x){let e=y+"_"+C+"."+i;x.file(e,n,{base64:false});C++;w()}else{let e=y+"_"+v+"_"+C+"."+i;const t=document.createElement("a");t.download=e;t.href=URL.createObjectURL(n);setTimeout(()=>{if(p.isLinked()){N(n,e=>{p.set(e)})}else{p.set(null)}if(u.get()){t.click()}C++;w()},200)}}else{o.log("screenshot: no blob")}},!c.get(),n,f.get())}}else{g.set("Prerendering...");o.log("pre ",C,D);o.patch.cgl.screenShot(e=>{C++;w()})}}function N(e,t){let n=new FileReader;n.onload=function(e){t(e.target.result)};n.readAsDataURL(e)}};Ops.Gl.RenderAnim_v2.prototype=new CABLES.Op;CABLES.OPS["c05e54a3-3ed5-4941-a412-01134f53f0ac"]={f:Ops.Gl.RenderAnim_v2,objName:"Ops.Gl.RenderAnim_v2"};Ops.Gl.Meshes.FullscreenRectangle=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={shader_frag:"UNI sampler2D tex;\nIN vec2 texCoord;\n\nvoid main()\n{\n    outColor= texture(tex,texCoord);\n}\n\n",shader_vert:"{{MODULES_HEAD}}\n\nIN vec3 vPosition;\nUNI mat4 projMatrix;\nUNI mat4 mvMatrix;\n\nOUT vec2 texCoord;\nIN vec2 attrTexCoord;\n\nvoid main()\n{\n   vec4 pos=vec4(vPosition,  1.0);\n\n   texCoord=vec2(attrTexCoord.x,(1.0-attrTexCoord.y));\n\n   gl_Position = projMatrix * mvMatrix * pos;\n}\n"};const n=e.inTrigger("render"),i=e.inSwitch("Scale",["Stretch","Fit"],"Fit"),r=e.inValueBool("Flip Y"),s=e.inValueBool("Flip X"),a=e.inTexture("Texture"),o=e.outTrigger("trigger");const l=e.patch.cgl;let h=null;let u=new CGL.Geometry("fullscreen rectangle");let f=0,c=0,d=0,m=0,g=0;e.toWorkShouldNotBeChild("Ops.Gl.TextureEffects.ImageCompose",CABLES.OP_PORT_TYPE_FUNCTION);e.toWorkPortsNeedToBeLinked(n);s.onChange=D;r.onChange=D;n.onTriggered=B;a.onLinkChanged=E;i.onChange=b;const p=new CGL.Shader(l,"fullscreenrectangle",this);p.setModules(["MODULE_VERTEX_POSITION","MODULE_COLOR","MODULE_BEGIN_FRAG"]);p.setSource(t.shader_vert,t.shader_frag);p.fullscreenRectUniform=new CGL.Uniform(p,"t","tex",0);p.aspectUni=new CGL.Uniform(p,"f","aspectTex",0);let F=false;let A=true;let C=false;let _=[];E();b();a.onChange=function(){A=true};function E(){if(!CABLES.UI)return;r.setUiAttribs({greyout:!a.isLinked()});s.setUiAttribs({greyout:!a.isLinked()});i.setUiAttribs({greyout:!a.isLinked()})}function v(){let e=a.get();if(e)F=true;else F=false}e.preRender=function(){v();p.bind();if(h)h.render(p);B()};function b(){C=i.get()=="Fit"}function B(){if(l.getViewPort()[2]!=m||l.getViewPort()[3]!=g||!h)y();if(A)v();l.pushPMatrix();mat4.identity(l.pMatrix);mat4.ortho(l.pMatrix,0,m,g,0,-10,1e3);l.pushModelMatrix();mat4.identity(l.mMatrix);l.pushViewMatrix();mat4.identity(l.vMatrix);if(C&&a.get()){const n=a.get().width/a.get().height;let e=g;let t=g*n;if(t>m){e=m*1/n;t=m}_[0]=l.getViewPort()[0];_[1]=l.getViewPort()[1];_[2]=l.getViewPort()[2];_[3]=l.getViewPort()[3];l.setViewPort((m-t)/2,(g-e)/2,t,e)}if(F){if(a.get())l.setTexture(0,a.get().tex);h.render(p)}else{h.render(l.getShader())}l.gl.clear(l.gl.DEPTH_BUFFER_BIT);l.popPMatrix();l.popModelMatrix();l.popViewMatrix();if(C&&a.get())l.setViewPort(_[0],_[1],_[2],_[3]);o.trigger()}function D(){h=null}function y(){const e=l.getViewPort();if(e[2]==m&&e[3]==g&&h)return;let t=0,n=0;m=e[2];g=e[3];u.vertices=new Float32Array([t+m,n+g,0,t,n+g,0,t+m,n,0,t,n,0]);let i=null;if(r.get())i=new Float32Array([1,0,0,0,1,1,0,1]);else i=new Float32Array([1,1,0,1,1,0,0,0]);if(s.get()){i[0]=0;i[2]=1;i[4]=0;i[6]=1}u.setTexCoords(i);u.verticesIndices=new Uint16Array([2,1,0,3,1,2]);u.vertexNormals=new Float32Array([0,0,1,0,0,1,0,0,1,0,0,1]);u.tangents=new Float32Array([-1,0,0,-1,0,0,-1,0,0,-1,0,0]);u.biTangents==new Float32Array([0,-1,0,0,-1,0,0,-1,0,0,-1,0]);if(!h)h=new CGL.Mesh(l,u);else h.setGeom(u)}};Ops.Gl.Meshes.FullscreenRectangle.prototype=new CABLES.Op;CABLES.OPS["255bd15b-cc91-4a12-9b4e-53c710cbb282"]={f:Ops.Gl.Meshes.FullscreenRectangle,objName:"Ops.Gl.Meshes.FullscreenRectangle"};Ops.Gl.ImageCompose.Levels_v2=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={levels_frag:"IN vec2 texCoord;\nUNI sampler2D tex;\nUNI float inMin;\nUNI float inMax;\nUNI float midPoint;\nUNI float outMax;\nUNI float outMin;\n\nvoid main()\n{\n    vec4 baseRGBA=texture(tex,texCoord);\n    vec3 base=baseRGBA.rgb;\n    vec3 inputRange = min(max(base - vec3(inMin), vec3(0.0)) / (vec3(inMax) - vec3(inMin)), vec3(outMax));\n\n    inputRange = pow(inputRange, vec3(1.0 / (1.5 - midPoint)));\n\n    outColor= vec4(mix(vec3(outMin), vec3(1.0), inputRange) ,baseRGBA.a);\n}"};const n=e.inTrigger("Render"),i=e.inValueSlider("In Min",0),r=e.inValueSlider("Midpoint",.5),s=e.inValueSlider("In Max",1),a=e.inValueSlider("Out Min",0),o=e.inValueSlider("Out Max",1),l=e.outTrigger("Next");const h=e.patch.cgl;const u=new CGL.Shader(h,e.name,e);const f=new CGL.Uniform(u,"f","inMin",i),c=new CGL.Uniform(u,"f","midPoint",r),d=new CGL.Uniform(u,"f","inMax",s),m=new CGL.Uniform(u,"f","outMin",a),g=new CGL.Uniform(u,"f","outMax",o),p=new CGL.Uniform(u,"t","tex",0);u.setSource(u.getDefaultVertexShader(),t.levels_frag);n.onTriggered=function(){if(!CGL.TextureEffect.checkOpInEffect(e,3))return;h.pushShader(u);h.currentTextureEffect.bind();h.setTexture(0,h.currentTextureEffect.getCurrentSourceTexture().tex);h.currentTextureEffect.finish();h.popShader();l.trigger()}};Ops.Gl.ImageCompose.Levels_v2.prototype=new CABLES.Op;CABLES.OPS["cf49063c-a010-4e2b-add6-f8dea50392b5"]={f:Ops.Gl.ImageCompose.Levels_v2,objName:"Ops.Gl.ImageCompose.Levels_v2"};Ops.WebAudio.AudioBuffer_v2=function(){CABLES.Op.apply(this,arguments);const i=this;const e=i.attachments={};const r=i.patch.cgl;const t=CABLES.WEBAUDIO.createAudioContext(i),n=i.inUrl("URL","audio"),s=i.inBool("Create Loading Task",true),a=i.outObject("Audio Buffer",null,"audioBuffer"),o=i.outBoolNum("Finished Loading",false),l=i.outNumber("Sample Rate",0),h=i.outNumber("Length",0),u=i.outNumber("Duration",0),f=i.outNumber("Number of Channels",0),c=i.outBool("isLoading",0);let d=null;let m=false;let g=null;let p=null;let F=false;let A=false;let C=false;let _=new FileReader;let E=null;let v=0;if(!a.isLinked()){i.setUiError("notConnected","To play back sound, connect this op to a playback operator such as SamplePlayer or AudioBufferPlayer.",0)}else{i.setUiError("notConnected",null)}a.onLinkChanged=()=>{if(a.isLinked()){i.setUiError("notConnected",null)}else{i.setUiError("notConnected","To play back sound, connect this op to a playback operator such as SamplePlayer or AudioBufferPlayer.",0)}};function b(t,e){g=t;m=true;c.set(m);if(!e){const n=t.substr(t.lastIndexOf(".")+1);if(n==="wav"){i.setUiError("wavFormat","You are using a .wav file. Make sure the .wav file is 16 bit to be supported by all browsers. Safari does not support 24 bit .wav files.",1)}else{i.setUiError("wavFormat",null)}CABLES.WEBAUDIO.loadAudioFile(i.patch,t,y,x,s.get())}else{let e=B(t);if(e.type==="audio/wav"){i.setUiError("wavFormat","You are using a .wav file. Make sure the .wav file is 16 bit to be supported by all browsers. Safari does not support 24 bit .wav files.",1)}else{i.setUiError("wavFormat",null)}if(s.get()){v=r.patch.loading.start("audiobuffer from data-url "+i.id,t,i);if(r.patch.isEditorMode())gui.jobs().start({id:"loadaudio"+v,title:" loading audio data url ("+i.id+")"})}_.readAsArrayBuffer(e)}}function B(e){let t=atob(e.split(",")[1]);let n=e.split(",")[0].split(":")[1].split(";")[0];let i=new ArrayBuffer(t.length);let r=new Uint8Array(i);for(let e=0;e<t.length;e++){r[e]=t.charCodeAt(e)}let s=new Blob([i],{type:n});return s}n.onChange=function(){if(n.get()){A=String(n.get()).indexOf("data:")==0;if(m){C=String(n.get()).indexOf("data:")==0;const t=C?n.get():i.patch.getFilePath(n.get());if(t!==g){p=t}else{p=null}F=false;return}S();const e=A?n.get():i.patch.getFilePath(n.get());b(e,A)}else{if(m){F=true;return}S();i.setUiError("wavFormat",null);i.setUiError("failedLoading",null)}};_.onloadend=()=>{E=_.result;r.patch.loading.finished(v);if(r.patch.isEditorMode())gui.jobs().finish("loadaudio"+v);D()};function D(){if(E)t.decodeAudioData(E,y,x)}function y(e){m=false;c.set(m);if(F){S();F=false;return}if(p){b(p,C);p=null}else{d=e;h.set(e.length);u.set(e.duration);f.set(e.numberOfChannels);l.set(e.sampleRate);a.set(e);i.setUiError("failedLoading",null);o.set(true);A=false;C=false}}function x(e){i.setUiError("failedLoading","The audio file could not be loaded. Make sure the right file URL is used.",2);m=false;S();c.set(m);d=null;if(p){b(p,C);p=null}}function S(){h.set(0);u.set(0);f.set(0);l.set(0);a.set(null);o.set(false)}};Ops.WebAudio.AudioBuffer_v2.prototype=new CABLES.Op;CABLES.OPS["5f1d6a2f-1c04-4744-b0fb-910825beceee"]={f:Ops.WebAudio.AudioBuffer_v2,objName:"Ops.WebAudio.AudioBuffer_v2"};Ops.WebAudio.AudioBufferPlayer_v2=function(){CABLES.Op.apply(this,arguments);const n=this;const e=n.attachments={};const i=n.inObject("Audio Buffer",null,"audioBuffer");const r=n.inBool("Start / Stop",false);const s=n.inBool("Loop",false);const t=n.inTriggerButton("Restart");const a=n.inFloat("Offset",0);const o=n.inFloat("Playback Rate",1);const l=n.inFloat("Detune",0);n.setPortGroup("Playback Controls",[r,s,t]);n.setPortGroup("Time Controls",[a]);n.setPortGroup("Miscellaneous",[o,l]);const h=n.outObject("Audio Out",null,"audioNode");const u=n.outBool("Is Playing",false);const f=n.outBool("Loading",false);let c=null;let d=false;let m=false;let g=null;let p=null;let F=false;const A=CABLES.WEBAUDIO.createAudioContext(n);const C=A.createGain();if(!i.isLinked()){n.setUiError("inputNotConnected","To be able to play back sound, you need to connect an AudioBuffer to this op.",0)}else{n.setUiError("inputNotConnected",null)}i.onLinkChanged=()=>{if(!i.isLinked()){n.setUiError("inputNotConnected","To be able to play back sound, you need to connect an AudioBuffer to this op.",0)}else{n.setUiError("inputNotConnected",null)}};if(!h.isLinked()){n.setUiError("outputNotConnected","To be able to hear sound playing, you need to connect this op to an Output op.",0)}else{n.setUiError("outputNotConnected",null)}h.onLinkChanged=()=>{if(!h.isLinked()){n.setUiError("outputNotConnected","To be able to hear sound playing, you need to connect this op to an Output op.",0)}else{n.setUiError("outputNotConnected",null)}};i.onChange=function(){if(i.get())b();else{if(F){F=false;f.set(F)}if(d){S(0);if(c)c.buffer=null;c=null}}};r.onChange=function(){if(!i.get())return;if(!c){if(!F)b()}if(r.get()){const e=0;y(e)}else{const t=0;S(t)}};s.onChange=function(){if(c){c.loop=!!s.get()}};l.onChange=_;function _(){if(!c)return;const e=l.get()||0;if(c.detune){c.detune.setValueAtTime(e,A.currentTime)}}o.onChange=E;function E(){if(!c)return;const e=o.get()||0;if(e>=c.playbackRate.minValue&&e<=c.playbackRate.maxValue){c.playbackRate.setValueAtTime(e,A.currentTime)}}let v=false;t.onTriggered=function(){if(!c)return;if(!i.get())return;else{if(!(i.get()instanceof AudioBuffer))return}if(r.get()){if(d){v=true;S(0)}else{y(0)}}};function b(e=false){if(F)return;if(!(i.get()instanceof AudioBuffer))return;F=true;f.set(F);if(c){c.onended=null;if(c.buffer){S(0);c.disconnect(C);c.buffer=null}c=null}c=A.createBufferSource();const t=i.get();if(!t){F=false;f.set(F);return}c.buffer=t;c.onended=T;c.loop=s.get();c.connect(C);E();_();h.set(C);F=false;f.set(F);if(v){y(0);v=false;return}if(r.get()&&!e){y(0)}}let B=false;let D=null;a.onChange=()=>{if(a.get()>=0)n.setUiError("offsetNegative",null);else{n.setUiError("offsetNegative","Offset cannot be negative. Setting to 0.",1)}if(c){if(c.buffer){if(a.get()>c.buffer.duration){n.setUiError("offsetTooLong","Your offset value is higher than the total time of your audio file. Please decrease the duration to be able to hear sound when playing back your buffer.",1)}else{n.setUiError("offsetTooLong",null)}}}};function y(t){try{if(c){let e=Math.max(0,a.get());c.start(t,e);d=true;m=false;u.set(true)}else{n.log("start() but no src...")}}catch(e){n.log("Error on start: ",e.message);u.set(false);d=false}}function x(){let e=!s.get();b(e)}function S(e){try{if(c){c.stop();if(!v)x()}d=false;u.set(false)}catch(e){n.setUiError(e);u.set(false)}}function T(){if(s.get()){d=true;m=false}else{d=false;m=true}u.set(d);x()}};Ops.WebAudio.AudioBufferPlayer_v2.prototype=new CABLES.Op;CABLES.OPS["3abd0dbb-eeee-4c65-ae31-b8bc2345e2d5"]={f:Ops.WebAudio.AudioBufferPlayer_v2,objName:"Ops.WebAudio.AudioBufferPlayer_v2"};Ops.WebAudio.Output_v2=function(){CABLES.Op.apply(this,arguments);const r=this;const e=r.attachments={};const t=r.inObject("Audio In",null,"audioNode"),s=r.inFloatSlider("Volume",1),a=r.inBool("Mute",false),n=r.inBool("Show Audio Suspended Button",true),o=r.outNumber("Current Volume",0),i=r.outString("Context State","unknown");r.setPortGroup("Volume Settings",[a,s]);let l=false;let h=CABLES.WEBAUDIO.createAudioContext(r);let u=h.createGain();const f=h.destination;let c=null;let d=false;a.onChange=()=>{F(a.get());A()};s.onChange=p;r.onMasterVolumeChanged=p;let m=r.patch.on("pause",p);let g=r.patch.on("resume",p);h.addEventListener("statechange",A);n.onChange=C;A();C();r.onDelete=()=>{if(u)u.disconnect();u=null;if(CABLES.interActionNeededButton)CABLES.interActionNeededButton.remove("audiosuspended");if(m)r.patch.off(m);if(g)r.patch.off(g)};t.onChange=function(){if(!t.get()){if(c){try{if(c.disconnect){c.disconnect(u)}}catch(e){r.logError(e)}}r.setUiError("multipleInputs",null);if(d){if(u)u.disconnect(f);d=false}}else{if(t.links.length>1)r.setUiError("multipleInputs","You have connected multiple inputs. It is possible that you experience unexpected behaviour. Please use a Mixer op to connect multiple audio streams.",1);else r.setUiError("multipleInputs",null);if(t.get().connect)t.get().connect(u)}c=t.get();if(!d){if(u)u.connect(f);d=true}p()};function p(e){const t=r.patch.config.masterVolume||0;let n=s.get()*t;if(r.patch._paused||a.get())n=0;let i=.05;if(e)i=.2;n=CABLES.clamp(n,0,1);if(!u)r.logError("gainNode undefined");if(u)u.gain.linearRampToValueAtTime(n,h.currentTime+i);o.set(n)}function F(e){if(e){if(h.state==="suspended"){if(u){u.gain.cancelScheduledValues(h.currentTime);u.gain.value=0;u.gain.setValueAtTime(0,h.currentTime)}o.set(0);return}}p(true)}function A(){i.set(h.state);r.logVerbose("audioCtx.state change",h.state);r.setUiError("ctxSusp",null);if(h.state=="suspended"){const t="Your Browser suspended audio context, use playButton op to play audio after a user interaction";let e=1;if(a.get())e=0;r.setUiError("ctxSusp",t,e)}C()}function C(){if(h.state=="suspended"){F(true);if(n.get()){l=true;if(CABLES.interActionNeededButton){CABLES.interActionNeededButton.add(r.patch,"audiosuspended",()=>{if(h&&h.state=="suspended"){h.resume();if(CABLES.interActionNeededButton)CABLES.interActionNeededButton.remove("audiosuspended")}})}}else{if(CABLES.interActionNeededButton)CABLES.interActionNeededButton.remove("audiosuspended")}}else{if(CABLES.interActionNeededButton)CABLES.interActionNeededButton.remove("audiosuspended");if(l){r.log("was suspended - set vol");p(true)}}}};Ops.WebAudio.Output_v2.prototype=new CABLES.Op;CABLES.OPS["90b95403-b0c4-4980-ab3b-b6c354771c81"]={f:Ops.WebAudio.Output_v2,objName:"Ops.WebAudio.Output_v2"};Ops.TimeLine.TimeLineControls=function(){CABLES.Op.apply(this,arguments);const e=this;const t=e.attachments={};const n=e.outBoolNum("Play/Stop");const i=e.outNumber("time");e.patch.timer.on("playPause",r);e.patch.timer.on("timeChange",r);function r(){n.set(false);setTimeout(function(){i.set(e.patch.timer.getTime());n.set(e.patch.timer.isPlaying())},10)}};Ops.TimeLine.TimeLineControls.prototype=new CABLES.Op;CABLES.OPS["53cb7b1a-56c7-405f-b427-12db78fbfd2f"]={f:Ops.TimeLine.TimeLineControls,objName:"Ops.TimeLine.TimeLineControls"};window.addEventListener("load",function(e){CABLES.jsLoaded=new Event("CABLES.jsLoaded");document.dispatchEvent(CABLES.jsLoaded)});window.Whammy=function(){function i(t,n){const e=g(t);const i=3e4;const r=[{id:440786851,data:[{data:1,id:17030},{data:1,id:17143},{data:4,id:17138},{data:8,id:17139},{data:"webm",id:17026},{data:2,id:17031},{data:2,id:17029}]},{id:408125543,data:[{id:357149030,data:[{data:1e6,id:2807729},{data:"whammy",id:19840},{data:"whammy",id:22337},{data:C(e.duration),id:17545}]},{id:374648427,data:[{id:174,data:[{data:1,id:215},{data:1,id:29637},{data:0,id:156},{data:"und",id:2274716},{data:"V_VP8",id:134},{data:"VP8",id:2459272},{data:1,id:131},{id:224,data:[{data:e.width,id:176},{data:e.height,id:186}]}]}]},{id:475249515,data:[]}]}];const s=r[1];const a=s.data[2];let o=0;let l=0;while(o<t.length){const f={id:187,data:[{data:Math.round(l),id:179},{id:183,data:[{data:1,id:247},{data:0,size:8,id:241}]}]};a.data.push(f);const c=[];let e=0;do{c.push(t[o]);e+=t[o].duration;o++}while(o<t.length&&e<i);var h=0;const d={id:524531317,data:[{data:Math.round(l),id:231}].concat(c.map(function(e){const t=A({discardable:0,frame:e.data.slice(e.data.indexOf("*")-3),invisible:0,keyframe:1,lacing:0,trackNum:1,timecode:Math.round(h)});h+=e.duration;return{data:t,id:163}}))};s.data.push(d);l+=e}let u=0;for(let e=0;e<s.data.length;e++){if(e>=3){a.data[e-3].data[1].data[1].data=u}const m=p([s.data[e]],n);u+=m.size||m.byteLength||m.length;if(e!=2){s.data[e]=m}}return p(r,n)}function g(t){let n=t[0].width,i=t[0].height,r=t[0].duration;for(let e=1;e<t.length;e++){if(t[e].width!=n)throw"Frame "+(e+1)+" has a different width";if(t[e].height!=i)throw"Frame "+(e+1)+" has a different height";if(t[e].duration<0||t[e].duration>32767)throw"Frame "+(e+1)+" has a weird duration (must be between 0 and 32767)";r+=t[e].duration}return{duration:r,width:n,height:i}}function f(e){const t=[];while(e>0){t.push(e&255);e>>=8}return new Uint8Array(t.reverse())}function c(t,n){const i=new Uint8Array(n);for(let e=n-1;e>=0;e--){i[e]=t&255;t>>=8}return i}function d(t){const n=new Uint8Array(t.length);for(let e=0;e<t.length;e++){n[e]=t.charCodeAt(e)}return n}function m(t){const n=[];const e=t.length%8?new Array(1+8-t.length%8).join("0"):"";t=e+t;for(let e=0;e<t.length;e+=8){n.push(parseInt(t.substr(e,8),2))}return new Uint8Array(n)}function p(n,i){const r=[];for(let t=0;t<n.length;t++){if(!("id"in n[t])){r.push(n[t]);continue}let e=n[t].data;if(typeof e=="object")e=p(e,i);if(typeof e=="number")e="size"in n[t]?c(e,n[t].size):m(e.toString(2));if(typeof e=="string")e=d(e);if(e.length){var s=s}const a=e.size||e.byteLength||e.length;const o=Math.ceil(Math.ceil(Math.log(a)/Math.log(2))/8);const l=a.toString(2);const h=new Array(o*7+7+1-l.length).join("0")+l;const u=new Array(o).join("0")+"1"+h;r.push(f(n[t].id));r.push(m(u));r.push(e)}if(i){const e=F(r);return new Uint8Array(e)}else{return new Blob(r,{type:"video/webm"})}}function F(t,n){if(n==null){n=[]}for(let e=0;e<t.length;e++){if(typeof t[e]=="object"){F(t[e],n)}else{n.push(t[e])}}return n}function h(t){let n="";const e=t.length%8?new Array(1+8-t.length%8).join("0"):"";t=e+t;for(let e=0;e<t.length;e+=8){n+=String.fromCharCode(parseInt(t.substr(e,8),2))}return n}function u(n){let i="";for(let t=0;t<n.length;t++){let e=n[t].data;if(typeof e=="object")e=u(e);if(typeof e=="number")e=h(e.toString(2));const r=e.length;const s=Math.ceil(Math.ceil(Math.log(r)/Math.log(2))/8);const a=r.toString(2);const o=new Array(s*7+7+1-a.length).join("0")+a;const l=new Array(s).join("0")+"1"+o;i+=h(n[t].id.toString(2))+h(l)+e}return i}function A(e){let t=0;if(e.keyframe)t|=128;if(e.invisible)t|=8;if(e.lacing)t|=e.lacing<<1;if(e.discardable)t|=1;if(e.trackNum>127){throw"TrackNumber > 127 not supported"}const n=[e.trackNum|128,e.timecode>>8,e.timecode&255,t].map(function(e){return String.fromCharCode(e)}).join("")+e.frame;return n}function r(e){const t=e.RIFF[0].WEBP[0];const n=t.indexOf("*");for(var i=0,r=[];i<4;i++)r[i]=t.charCodeAt(n+3+i);let s,a,o,l,h;h=r[1]<<8|r[0];s=h&16383;a=h>>14;h=r[3]<<8|r[2];o=h&16383;l=h>>14;return{width:s,height:o,data:t,riff:e}}function a(e){let t=0;const n={};while(t<e.length){const i=e.substr(t,4);n[i]=n[i]||[];if(i=="RIFF"||i=="LIST"){const r=parseInt(e.substr(t+4,4).split("").map(function(e){const t=e.charCodeAt(0).toString(2);return new Array(8-t.length+1).join("0")+t}).join(""),2);const s=e.substr(t+4+4,r);t+=4+4+r;n[i].push(a(s))}else if(i=="WEBP"){n[i].push(e.substr(t+8));t=e.length}else{n[i].push(e.substr(t+4));t=e.length}}return n}function C(e){return[].slice.call(new Uint8Array(new Float64Array([e]).buffer),0).map(function(e){return String.fromCharCode(e)}).reverse().join("")}function e(e,t){this.frames=[];this.duration=1e3/e;this.quality=t||.8}e.prototype.add=function(e,t){if(typeof t!="undefined"&&this.duration)throw"you can't pass a duration if the fps is set";if(typeof t=="undefined"&&!this.duration)throw"if you don't have the fps set, you need to have durations here.";if(e.canvas){e=e.canvas}if(e.toDataURL){e=e.getContext("2d").getImageData(0,0,e.width,e.height)}else if(typeof e!="string"){throw"frame must be a a HTMLCanvasElement, a CanvasRenderingContext2D or a DataURI formatted string"}if(typeof e==="string"&&!/^data:image\/webp;base64,/gi.test(e)){throw"Input must be formatted properly as a base64 encoded DataURI of type image/webp"}this.frames.push({image:e,duration:t||this.duration})};e.prototype.encodeFrames=function(n){if(this.frames[0].image instanceof ImageData){const r=this.frames;const s=document.createElement("canvas");const a=s.getContext("2d");s.width=this.frames[0].image.width;s.height=this.frames[0].image.height;var i=function(e){console.log("encodeFrame",e);const t=r[e];a.putImageData(t.image,0,0);t.image=s.toDataURL("image/webp",this.quality);if(e<r.length-1){setTimeout(function(){i(e+1)},1)}else{n()}}.bind(this);i(0)}else{n()}};e.prototype.compile=function(t,n){this.encodeFrames(function(){const e=new i(this.frames.map(function(e){const t=r(a(atob(e.image.slice(23))));t.duration=e.duration;return t}),t);n(e)}.bind(this))};return{Video:e,fromImageArray:function(e,n,t){return i(e.map(function(e){const t=r(a(atob(e.slice(23))));t.duration=1e3/n;return t}),t)},toWebM:i}}();(function(e){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=e()}else if(typeof define==="function"&&define.amd){define([],e)}else{var t;if(typeof window!=="undefined"){t=window}else if(typeof global!=="undefined"){t=global}else if(typeof self!=="undefined"){t=self}else{t=this}t.JSZip=e()}})(function(){var e,t,n;return function s(a,o,l){function h(n,e){if(!o[n]){if(!a[n]){var t=typeof require=="function"&&require;if(!e&&t)return t(n,!0);if(u)return u(n,!0);var i=new Error("Cannot find module '"+n+"'");throw i.code="MODULE_NOT_FOUND",i}var r=o[n]={exports:{}};a[n][0].call(r.exports,function(e){var t=a[n][1][e];return h(t?t:e)},r,r.exports,s,a,o,l)}return o[n].exports}var u=typeof require=="function"&&require;for(var e=0;e<l.length;e++)h(l[e]);return h}({1:[function(e,t,n){"use strict";var d=e("./utils");var m=e("./support");var g="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";n.encode=function(e){var t=[];var n,i,r,s,a,o,l;var h=0,u=e.length,f=u;var c=d.getTypeOf(e)!=="string";while(h<e.length){f=u-h;if(!c){n=e.charCodeAt(h++);i=h<u?e.charCodeAt(h++):0;r=h<u?e.charCodeAt(h++):0}else{n=e[h++];i=h<u?e[h++]:0;r=h<u?e[h++]:0}s=n>>2;a=(n&3)<<4|i>>4;o=f>1?(i&15)<<2|r>>6:64;l=f>2?r&63:64;t.push(g.charAt(s)+g.charAt(a)+g.charAt(o)+g.charAt(l))}return t.join("")};n.decode=function(e){var t,n,i;var r,s,a,o;var l=0,h=0;var u="data:";if(e.substr(0,u.length)===u){throw new Error("Invalid base64 input, it looks like a data url.")}e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");var f=e.length*3/4;if(e.charAt(e.length-1)===g.charAt(64)){f--}if(e.charAt(e.length-2)===g.charAt(64)){f--}if(f%1!==0){throw new Error("Invalid base64 input, bad content length.")}var c;if(m.uint8array){c=new Uint8Array(f|0)}else{c=new Array(f|0)}while(l<e.length){r=g.indexOf(e.charAt(l++));s=g.indexOf(e.charAt(l++));a=g.indexOf(e.charAt(l++));o=g.indexOf(e.charAt(l++));t=r<<2|s>>4;n=(s&15)<<4|a>>2;i=(a&3)<<6|o;c[h++]=t;if(a!==64){c[h++]=n}if(o!==64){c[h++]=i}}return c}},{"./support":30,"./utils":32}],2:[function(e,t,n){"use strict";var i=e("./external");var r=e("./stream/DataWorker");var s=e("./stream/DataLengthProbe");var a=e("./stream/Crc32Probe");var s=e("./stream/DataLengthProbe");function o(e,t,n,i,r){this.compressedSize=e;this.uncompressedSize=t;this.crc32=n;this.compression=i;this.compressedContent=r}o.prototype={getContentWorker:function(){var e=new r(i.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new s("data_length"));var t=this;e.on("end",function(){if(this.streamInfo["data_length"]!==t.uncompressedSize){throw new Error("Bug : uncompressed data size mismatch")}});return e},getCompressedWorker:function(){return new r(i.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}};o.createWorkerFrom=function(e,t,n){return e.pipe(new a).pipe(new s("uncompressedSize")).pipe(t.compressWorker(n)).pipe(new s("compressedSize")).withStreamInfo("compression",t)};t.exports=o},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(e,t,n){"use strict";var i=e("./stream/GenericWorker");n.STORE={magic:"\0\0",compressWorker:function(e){return new i("STORE compression")},uncompressWorker:function(){return new i("STORE decompression")}};n.DEFLATE=e("./flate")},{"./flate":7,"./stream/GenericWorker":28}],4:[function(e,t,n){"use strict";var r=e("./utils");function i(){var e,t=[];for(var n=0;n<256;n++){e=n;for(var i=0;i<8;i++){e=e&1?3988292384^e>>>1:e>>>1}t[n]=e}return t}var o=i();function s(e,t,n,i){var r=o,s=i+n;e=e^-1;for(var a=i;a<s;a++){e=e>>>8^r[(e^t[a])&255]}return e^-1}function a(e,t,n,i){var r=o,s=i+n;e=e^-1;for(var a=i;a<s;a++){e=e>>>8^r[(e^t.charCodeAt(a))&255]}return e^-1}t.exports=function e(t,n){if(typeof t==="undefined"||!t.length){return 0}var i=r.getTypeOf(t)!=="string";if(i){return s(n|0,t,t.length,0)}else{return a(n|0,t,t.length,0)}}},{"./utils":32}],5:[function(e,t,n){"use strict";n.base64=false;n.binary=false;n.dir=false;n.createFolders=true;n.date=null;n.compression=null;n.compressionOptions=null;n.comment=null;n.unixPermissions=null;n.dosPermissions=null},{}],6:[function(e,t,n){"use strict";var i=null;if(typeof Promise!=="undefined"){i=Promise}else{i=e("lie")}t.exports={Promise:i}},{lie:37}],7:[function(e,t,n){"use strict";var i=typeof Uint8Array!=="undefined"&&typeof Uint16Array!=="undefined"&&typeof Uint32Array!=="undefined";var r=e("pako");var s=e("./utils");var a=e("./stream/GenericWorker");var o=i?"uint8array":"array";n.magic="\b\0";function l(e,t){a.call(this,"FlateWorker/"+e);this._pako=null;this._pakoAction=e;this._pakoOptions=t;this.meta={}}s.inherits(l,a);l.prototype.processChunk=function(e){this.meta=e.meta;if(this._pako===null){this._createPako()}this._pako.push(s.transformTo(o,e.data),false)};l.prototype.flush=function(){a.prototype.flush.call(this);if(this._pako===null){this._createPako()}this._pako.push([],true)};l.prototype.cleanUp=function(){a.prototype.cleanUp.call(this);this._pako=null};l.prototype._createPako=function(){this._pako=new r[this._pakoAction]({raw:true,level:this._pakoOptions.level||-1});var t=this;this._pako.onData=function(e){t.push({data:e,meta:t.meta})}};n.compressWorker=function(e){return new l("Deflate",e)};n.uncompressWorker=function(){return new l("Inflate",{})}},{"./stream/GenericWorker":28,"./utils":32,pako:38}],8:[function(e,t,n){"use strict";var O=e("../utils");var r=e("../stream/GenericWorker");var I=e("../utf8");var w=e("../crc32");var L=e("../signature");var N=function(e,t){var n="",i;for(i=0;i<t;i++){n+=String.fromCharCode(e&255);e=e>>>8}return n};var R=function(e,t){var n=e;if(!e){n=t?16893:33204}return(n&65535)<<16};var k=function(e,t){return(e||0)&63};var i=function(e,t,n,i,r,s){var a=e["file"],o=e["compression"],l=s!==I.utf8encode,h=O.transformTo("string",s(a.name)),u=O.transformTo("string",I.utf8encode(a.name)),f=a.comment,c=O.transformTo("string",s(f)),d=O.transformTo("string",I.utf8encode(f)),m=u.length!==a.name.length,g=d.length!==f.length,p,F,A="",C="",_="",E=a.dir,v=a.date;var b={crc32:0,compressedSize:0,uncompressedSize:0};if(!t||n){b.crc32=e["crc32"];b.compressedSize=e["compressedSize"];b.uncompressedSize=e["uncompressedSize"]}var B=0;if(t){B|=8}if(!l&&(m||g)){B|=2048}var D=0;var y=0;if(E){D|=16}if(r==="UNIX"){y=798;D|=R(a.unixPermissions,E)}else{y=20;D|=k(a.dosPermissions,E)}p=v.getUTCHours();p=p<<6;p=p|v.getUTCMinutes();p=p<<5;p=p|v.getUTCSeconds()/2;F=v.getUTCFullYear()-1980;F=F<<4;F=F|v.getUTCMonth()+1;F=F<<5;F=F|v.getUTCDate();if(m){C=N(1,1)+N(w(h),4)+u;A+="up"+N(C.length,2)+C}if(g){_=N(1,1)+N(w(c),4)+d;A+="uc"+N(_.length,2)+_}var x="";x+="\n\0";x+=N(B,2);x+=o.magic;x+=N(p,2);x+=N(F,2);x+=N(b.crc32,4);x+=N(b.compressedSize,4);x+=N(b.uncompressedSize,4);x+=N(h.length,2);x+=N(A.length,2);var S=L.LOCAL_FILE_HEADER+x+h+A;var T=L.CENTRAL_FILE_HEADER+N(y,2)+x+N(c.length,2)+"\0\0"+"\0\0"+N(D,4)+N(i,4)+h+A+c;return{fileRecord:S,dirRecord:T}};var s=function(e,t,n,i,r){var s="";var a=O.transformTo("string",r(i));s=L.CENTRAL_DIRECTORY_END+"\0\0"+"\0\0"+N(e,2)+N(e,2)+N(t,4)+N(n,4)+N(a.length,2)+a;return s};var a=function(e){var t="";t=L.DATA_DESCRIPTOR+N(e["crc32"],4)+N(e["compressedSize"],4)+N(e["uncompressedSize"],4);return t};function o(e,t,n,i){r.call(this,"ZipFileWorker");this.bytesWritten=0;this.zipComment=t;this.zipPlatform=n;this.encodeFileName=i;this.streamFiles=e;this.accumulate=false;this.contentBuffer=[];this.dirRecords=[];this.currentSourceOffset=0;this.entriesCount=0;this.currentFile=null;this._sources=[]}O.inherits(o,r);o.prototype.push=function(e){var t=e.meta.percent||0;var n=this.entriesCount;var i=this._sources.length;if(this.accumulate){this.contentBuffer.push(e)}else{this.bytesWritten+=e.data.length;r.prototype.push.call(this,{data:e.data,meta:{currentFile:this.currentFile,percent:n?(t+100*(n-i-1))/n:100}})}};o.prototype.openedSource=function(e){this.currentSourceOffset=this.bytesWritten;this.currentFile=e["file"].name;var t=this.streamFiles&&!e["file"].dir;if(t){var n=i(e,t,false,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:n.fileRecord,meta:{percent:0}})}else{this.accumulate=true}};o.prototype.closedSource=function(e){this.accumulate=false;var t=this.streamFiles&&!e["file"].dir;var n=i(e,t,true,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.dirRecords.push(n.dirRecord);if(t){this.push({data:a(e),meta:{percent:100}})}else{this.push({data:n.fileRecord,meta:{percent:0}});while(this.contentBuffer.length){this.push(this.contentBuffer.shift())}}this.currentFile=null};o.prototype.flush=function(){var e=this.bytesWritten;for(var t=0;t<this.dirRecords.length;t++){this.push({data:this.dirRecords[t],meta:{percent:100}})}var n=this.bytesWritten-e;var i=s(this.dirRecords.length,n,e,this.zipComment,this.encodeFileName);this.push({data:i,meta:{percent:100}})};o.prototype.prepareNextSource=function(){this.previous=this._sources.shift();this.openedSource(this.previous.streamInfo);if(this.isPaused){this.previous.pause()}else{this.previous.resume()}};o.prototype.registerPrevious=function(e){this._sources.push(e);var t=this;e.on("data",function(e){t.processChunk(e)});e.on("end",function(){t.closedSource(t.previous.streamInfo);if(t._sources.length){t.prepareNextSource()}else{t.end()}});e.on("error",function(e){t.error(e)});return this};o.prototype.resume=function(){if(!r.prototype.resume.call(this)){return false}if(!this.previous&&this._sources.length){this.prepareNextSource();return true}if(!this.previous&&!this._sources.length&&!this.generatedError){this.end();return true}};o.prototype.error=function(e){var t=this._sources;if(!r.prototype.error.call(this,e)){return false}for(var n=0;n<t.length;n++){try{t[n].error(e)}catch(e){}}return true};o.prototype.lock=function(){r.prototype.lock.call(this);var e=this._sources;for(var t=0;t<e.length;t++){e[t].lock()}};t.exports=o},{"../crc32":4,"../signature":23,"../stream/GenericWorker":28,"../utf8":31,"../utils":32}],9:[function(e,t,n){"use strict";var r=e("../compressions");var i=e("./ZipFileWorker");var h=function(e,t){var n=e||t;var i=r[n];if(!i){throw new Error(n+" is not a valid compression method !")}return i};n.generateWorker=function(e,a,t){var o=new i(a.streamFiles,t,a.platform,a.encodeFileName);var l=0;try{e.forEach(function(e,t){l++;var n=h(t.options.compression,a.compression);var i=t.options.compressionOptions||a.compressionOptions||{};var r=t.dir,s=t.date;t._compressWorker(n,i).withStreamInfo("file",{name:e,dir:r,date:s,comment:t.comment||"",unixPermissions:t.unixPermissions,dosPermissions:t.dosPermissions}).pipe(o)});o.entriesCount=l}catch(e){o.error(e)}return o}},{"../compressions":3,"./ZipFileWorker":8}],10:[function(e,t,n){"use strict";function i(){if(!(this instanceof i)){return new i}if(arguments.length){throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.")}this.files={};this.comment=null;this.root="";this.clone=function(){var e=new i;for(var t in this){if(typeof this[t]!=="function"){e[t]=this[t]}}return e}}i.prototype=e("./object");i.prototype.loadAsync=e("./load");i.support=e("./support");i.defaults=e("./defaults");i.version="3.5.0";i.loadAsync=function(e,t){return(new i).loadAsync(e,t)};i.external=e("./external");t.exports=i},{"./defaults":5,"./external":6,"./load":11,"./object":15,"./support":30}],11:[function(e,t,n){"use strict";var i=e("./utils");var s=e("./external");var r=e("./utf8");var i=e("./utils");var l=e("./zipEntries");var a=e("./stream/Crc32Probe");var h=e("./nodejsUtils");function u(i){return new s.Promise(function(e,t){var n=i.decompressed.getContentWorker().pipe(new a);n.on("error",function(e){t(e)}).on("end",function(){if(n.streamInfo.crc32!==i.decompressed.crc32){t(new Error("Corrupted zip : CRC32 mismatch"))}else{e()}}).resume()})}t.exports=function(e,a){var o=this;a=i.extend(a||{},{base64:false,checkCRC32:false,optimizedBinaryString:false,createFolders:false,decodeFileName:r.utf8decode});if(h.isNode&&h.isStream(e)){return s.Promise.reject(new Error("JSZip can't accept a stream when loading a zip file."))}return i.prepareContent("the loaded zip file",e,true,a.optimizedBinaryString,a.base64).then(function(e){var t=new l(a);t.load(e);return t}).then(function e(t){var n=[s.Promise.resolve(t)];var i=t.files;if(a.checkCRC32){for(var r=0;r<i.length;r++){n.push(u(i[r]))}}return s.Promise.all(n)}).then(function e(t){var n=t.shift();var i=n.files;for(var r=0;r<i.length;r++){var s=i[r];o.file(s.fileNameStr,s.decompressed,{binary:true,optimizedBinaryString:true,date:s.date,dir:s.dir,comment:s.fileCommentStr.length?s.fileCommentStr:null,unixPermissions:s.unixPermissions,dosPermissions:s.dosPermissions,createFolders:a.createFolders})}if(n.zipComment.length){o.comment=n.zipComment}return o})}},{"./external":6,"./nodejsUtils":14,"./stream/Crc32Probe":25,"./utf8":31,"./utils":32,"./zipEntries":33}],12:[function(e,t,n){"use strict";var i=e("../utils");var r=e("../stream/GenericWorker");function s(e,t){r.call(this,"Nodejs stream input adapter for "+e);this._upstreamEnded=false;this._bindStream(t)}i.inherits(s,r);s.prototype._bindStream=function(e){var t=this;this._stream=e;e.pause();e.on("data",function(e){t.push({data:e,meta:{percent:0}})}).on("error",function(e){if(t.isPaused){this.generatedError=e}else{t.error(e)}}).on("end",function(){if(t.isPaused){t._upstreamEnded=true}else{t.end()}})};s.prototype.pause=function(){if(!r.prototype.pause.call(this)){return false}this._stream.pause();return true};s.prototype.resume=function(){if(!r.prototype.resume.call(this)){return false}if(this._upstreamEnded){this.end()}else{this._stream.resume()}return true};t.exports=s},{"../stream/GenericWorker":28,"../utils":32}],13:[function(e,t,n){"use strict";var r=e("readable-stream").Readable;var i=e("../utils");i.inherits(s,r);function s(e,t,n){r.call(this,t);this._helper=e;var i=this;e.on("data",function(e,t){if(!i.push(e)){i._helper.pause()}if(n){n(t)}}).on("error",function(e){i.emit("error",e)}).on("end",function(){i.push(null)})}s.prototype._read=function(){this._helper.resume()};t.exports=s},{"../utils":32,"readable-stream":16}],14:[function(e,t,n){"use strict";t.exports={isNode:typeof Buffer!=="undefined",newBufferFrom:function(e,t){if(Buffer.from&&Buffer.from!==Uint8Array.from){return Buffer.from(e,t)}else{if(typeof e==="number"){throw new Error('The "data" argument must not be a number')}return new Buffer(e,t)}},allocBuffer:function(e){if(Buffer.alloc){return Buffer.alloc(e)}else{var t=new Buffer(e);t.fill(0);return t}},isBuffer:function(e){return Buffer.isBuffer(e)},isStream:function(e){return e&&typeof e.on==="function"&&typeof e.pause==="function"&&typeof e.resume==="function"}}},{}],15:[function(e,t,n){"use strict";var r=e("./utf8");var u=e("./utils");var f=e("./stream/GenericWorker");var s=e("./stream/StreamHelper");var c=e("./defaults");var d=e("./compressedObject");var m=e("./zipObject");var a=e("./generate");var g=e("./nodejsUtils");var p=e("./nodejs/NodejsStreamInputAdapter");var o=function(e,t,n){var i=u.getTypeOf(t),r;var s=u.extend(n||{},c);s.date=s.date||new Date;if(s.compression!==null){s.compression=s.compression.toUpperCase()}if(typeof s.unixPermissions==="string"){s.unixPermissions=parseInt(s.unixPermissions,8)}if(s.unixPermissions&&s.unixPermissions&16384){s.dir=true}if(s.dosPermissions&&s.dosPermissions&16){s.dir=true}if(s.dir){e=A(e)}if(s.createFolders&&(r=F(e))){C.call(this,r,true)}var a=i==="string"&&s.binary===false&&s.base64===false;if(!n||typeof n.binary==="undefined"){s.binary=!a}var o=t instanceof d&&t.uncompressedSize===0;if(o||s.dir||!t||t.length===0){s.base64=false;s.binary=true;t="";s.compression="STORE";i="string"}var l=null;if(t instanceof d||t instanceof f){l=t}else if(g.isNode&&g.isStream(t)){l=new p(e,t)}else{l=u.prepareContent(e,t,s.binary,s.optimizedBinaryString,s.base64)}var h=new m(e,l,s);this.files[e]=h};var F=function(e){if(e.slice(-1)==="/"){e=e.substring(0,e.length-1)}var t=e.lastIndexOf("/");return t>0?e.substring(0,t):""};var A=function(e){if(e.slice(-1)!=="/"){e+="/"}return e};var C=function(e,t){t=typeof t!=="undefined"?t:c.createFolders;e=A(e);if(!this.files[e]){o.call(this,e,null,{dir:true,createFolders:t})}return this.files[e]};function l(e){return Object.prototype.toString.call(e)==="[object RegExp]"}var i={load:function(){throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.")},forEach:function(e){var t,n,i;for(t in this.files){if(!this.files.hasOwnProperty(t)){continue}i=this.files[t];n=t.slice(this.root.length,t.length);if(n&&t.slice(0,this.root.length)===this.root){e(n,i)}}},filter:function(n){var i=[];this.forEach(function(e,t){if(n(e,t)){i.push(t)}});return i},file:function(e,t,n){if(arguments.length===1){if(l(e)){var i=e;return this.filter(function(e,t){return!t.dir&&i.test(e)})}else{var r=this.files[this.root+e];if(r&&!r.dir){return r}else{return null}}}else{e=this.root+e;o.call(this,e,t,n)}return this},folder:function(n){if(!n){return this}if(l(n)){return this.filter(function(e,t){return t.dir&&n.test(e)})}var e=this.root+n;var t=C.call(this,e);var i=this.clone();i.root=t.name;return i},remove:function(n){n=this.root+n;var e=this.files[n];if(!e){if(n.slice(-1)!=="/"){n+="/"}e=this.files[n]}if(e&&!e.dir){delete this.files[n]}else{var t=this.filter(function(e,t){return t.name.slice(0,n.length)===n});for(var i=0;i<t.length;i++){delete this.files[t[i].name]}}return this},generate:function(e){throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.")},generateInternalStream:function(e){var t,n={};try{n=u.extend(e||{},{streamFiles:false,compression:"STORE",compressionOptions:null,type:"",platform:"DOS",comment:null,mimeType:"application/zip",encodeFileName:r.utf8encode});n.type=n.type.toLowerCase();n.compression=n.compression.toUpperCase();if(n.type==="binarystring"){n.type="string"}if(!n.type){throw new Error("No output type specified.")}u.checkSupport(n.type);if(n.platform==="darwin"||n.platform==="freebsd"||n.platform==="linux"||n.platform==="sunos"){n.platform="UNIX"}if(n.platform==="win32"){n.platform="DOS"}var i=n.comment||this.comment||"";t=a.generateWorker(this,n,i)}catch(e){t=new f("error");t.error(e)}return new s(t,n.type||"string",n.mimeType)},generateAsync:function(e,t){return this.generateInternalStream(e).accumulate(t)},generateNodeStream:function(e,t){e=e||{};if(!e.type){e.type="nodebuffer"}return this.generateInternalStream(e).toNodejsStream(t)}};t.exports=i},{"./compressedObject":2,"./defaults":5,"./generate":9,"./nodejs/NodejsStreamInputAdapter":12,"./nodejsUtils":14,"./stream/GenericWorker":28,"./stream/StreamHelper":29,"./utf8":31,"./utils":32,"./zipObject":35}],16:[function(e,t,n){t.exports=e("stream")},{stream:undefined}],17:[function(e,t,n){"use strict";var i=e("./DataReader");var r=e("../utils");function s(e){i.call(this,e);for(var t=0;t<this.data.length;t++){e[t]=e[t]&255}}r.inherits(s,i);s.prototype.byteAt=function(e){return this.data[this.zero+e]};s.prototype.lastIndexOfSignature=function(e){var t=e.charCodeAt(0),n=e.charCodeAt(1),i=e.charCodeAt(2),r=e.charCodeAt(3);for(var s=this.length-4;s>=0;--s){if(this.data[s]===t&&this.data[s+1]===n&&this.data[s+2]===i&&this.data[s+3]===r){return s-this.zero}}return-1};s.prototype.readAndCheckSignature=function(e){var t=e.charCodeAt(0),n=e.charCodeAt(1),i=e.charCodeAt(2),r=e.charCodeAt(3),s=this.readData(4);return t===s[0]&&n===s[1]&&i===s[2]&&r===s[3]};s.prototype.readData=function(e){this.checkOffset(e);if(e===0){return[]}var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);this.index+=e;return t};t.exports=s},{"../utils":32,"./DataReader":18}],18:[function(e,t,n){"use strict";var i=e("../utils");function r(e){this.data=e;this.length=e.length;this.index=0;this.zero=0}r.prototype={checkOffset:function(e){this.checkIndex(this.index+e)},checkIndex:function(e){if(this.length<this.zero+e||e<0){throw new Error("End of data reached (data length = "+this.length+", asked index = "+e+"). Corrupted zip ?")}},setIndex:function(e){this.checkIndex(e);this.index=e},skip:function(e){this.setIndex(this.index+e)},byteAt:function(e){},readInt:function(e){var t=0,n;this.checkOffset(e);for(n=this.index+e-1;n>=this.index;n--){t=(t<<8)+this.byteAt(n)}this.index+=e;return t},readString:function(e){return i.transformTo("string",this.readData(e))},readData:function(e){},lastIndexOfSignature:function(e){},readAndCheckSignature:function(e){},readDate:function(){var e=this.readInt(4);return new Date(Date.UTC((e>>25&127)+1980,(e>>21&15)-1,e>>16&31,e>>11&31,e>>5&63,(e&31)<<1))}};t.exports=r},{"../utils":32}],19:[function(e,t,n){"use strict";var i=e("./Uint8ArrayReader");var r=e("../utils");function s(e){i.call(this,e)}r.inherits(s,i);s.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);this.index+=e;return t};t.exports=s},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(e,t,n){"use strict";var i=e("./DataReader");var r=e("../utils");function s(e){i.call(this,e)}r.inherits(s,i);s.prototype.byteAt=function(e){return this.data.charCodeAt(this.zero+e)};s.prototype.lastIndexOfSignature=function(e){return this.data.lastIndexOf(e)-this.zero};s.prototype.readAndCheckSignature=function(e){var t=this.readData(4);return e===t};s.prototype.readData=function(e){this.checkOffset(e);var t=this.data.slice(this.zero+this.index,this.zero+this.index+e);this.index+=e;return t};t.exports=s},{"../utils":32,"./DataReader":18}],21:[function(e,t,n){"use strict";var i=e("./ArrayReader");var r=e("../utils");function s(e){i.call(this,e)}r.inherits(s,i);s.prototype.readData=function(e){this.checkOffset(e);if(e===0){return new Uint8Array(0)}var t=this.data.subarray(this.zero+this.index,this.zero+this.index+e);this.index+=e;return t};t.exports=s},{"../utils":32,"./ArrayReader":17}],22:[function(e,t,n){"use strict";var i=e("../utils");var r=e("../support");var s=e("./ArrayReader");var a=e("./StringReader");var o=e("./NodeBufferReader");var l=e("./Uint8ArrayReader");t.exports=function(e){var t=i.getTypeOf(e);i.checkSupport(t);if(t==="string"&&!r.uint8array){return new a(e)}if(t==="nodebuffer"){return new o(e)}if(r.uint8array){return new l(i.transformTo("uint8array",e))}return new s(i.transformTo("array",e))}},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(e,t,n){"use strict";n.LOCAL_FILE_HEADER="PK";n.CENTRAL_FILE_HEADER="PK";n.CENTRAL_DIRECTORY_END="PK";n.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK";n.ZIP64_CENTRAL_DIRECTORY_END="PK";n.DATA_DESCRIPTOR="PK\b"},{}],24:[function(e,t,n){"use strict";var i=e("./GenericWorker");var r=e("../utils");function s(e){i.call(this,"ConvertWorker to "+e);this.destType=e}r.inherits(s,i);s.prototype.processChunk=function(e){this.push({data:r.transformTo(this.destType,e.data),meta:e.meta})};t.exports=s},{"../utils":32,"./GenericWorker":28}],25:[function(e,t,n){"use strict";var i=e("./GenericWorker");var r=e("../crc32");var s=e("../utils");function a(){i.call(this,"Crc32Probe");this.withStreamInfo("crc32",0)}s.inherits(a,i);a.prototype.processChunk=function(e){this.streamInfo.crc32=r(e.data,this.streamInfo.crc32||0);this.push(e)};t.exports=a},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(e,t,n){"use strict";var i=e("../utils");var r=e("./GenericWorker");function s(e){r.call(this,"DataLengthProbe for "+e);this.propName=e;this.withStreamInfo(e,0)}i.inherits(s,r);s.prototype.processChunk=function(e){if(e){var t=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=t+e.data.length}r.prototype.processChunk.call(this,e)};t.exports=s},{"../utils":32,"./GenericWorker":28}],27:[function(e,t,n){"use strict";var i=e("../utils");var r=e("./GenericWorker");var s=16*1024;function a(e){r.call(this,"DataWorker");var t=this;this.dataIsReady=false;this.index=0;this.max=0;this.data=null;this.type="";this._tickScheduled=false;e.then(function(e){t.dataIsReady=true;t.data=e;t.max=e&&e.length||0;t.type=i.getTypeOf(e);if(!t.isPaused){t._tickAndRepeat()}},function(e){t.error(e)})}i.inherits(a,r);a.prototype.cleanUp=function(){r.prototype.cleanUp.call(this);this.data=null};a.prototype.resume=function(){if(!r.prototype.resume.call(this)){return false}if(!this._tickScheduled&&this.dataIsReady){this._tickScheduled=true;i.delay(this._tickAndRepeat,[],this)}return true};a.prototype._tickAndRepeat=function(){this._tickScheduled=false;if(this.isPaused||this.isFinished){return}this._tick();if(!this.isFinished){i.delay(this._tickAndRepeat,[],this);this._tickScheduled=true}};a.prototype._tick=function(){if(this.isPaused||this.isFinished){return false}var e=s;var t=null,n=Math.min(this.max,this.index+e);if(this.index>=this.max){return this.end()}else{switch(this.type){case"string":t=this.data.substring(this.index,n);break;case"uint8array":t=this.data.subarray(this.index,n);break;case"array":case"nodebuffer":t=this.data.slice(this.index,n);break}this.index=n;return this.push({data:t,meta:{percent:this.max?this.index/this.max*100:0}})}};t.exports=a},{"../utils":32,"./GenericWorker":28}],28:[function(e,t,n){"use strict";function i(e){this.name=e||"default";this.streamInfo={};this.generatedError=null;this.extraStreamInfo={};this.isPaused=true;this.isFinished=false;this.isLocked=false;this._listeners={data:[],end:[],error:[]};this.previous=null}i.prototype={push:function(e){this.emit("data",e)},end:function(){if(this.isFinished){return false}this.flush();try{this.emit("end");this.cleanUp();this.isFinished=true}catch(e){this.emit("error",e)}return true},error:function(e){if(this.isFinished){return false}if(this.isPaused){this.generatedError=e}else{this.isFinished=true;this.emit("error",e);if(this.previous){this.previous.error(e)}this.cleanUp()}return true},on:function(e,t){this._listeners[e].push(t);return this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null;this._listeners=[]},emit:function(e,t){if(this._listeners[e]){for(var n=0;n<this._listeners[e].length;n++){this._listeners[e][n].call(this,t)}}},pipe:function(e){return e.registerPrevious(this)},registerPrevious:function(e){if(this.isLocked){throw new Error("The stream '"+this+"' has already been used.")}this.streamInfo=e.streamInfo;this.mergeStreamInfo();this.previous=e;var t=this;e.on("data",function(e){t.processChunk(e)});e.on("end",function(){t.end()});e.on("error",function(e){t.error(e)});return this},pause:function(){if(this.isPaused||this.isFinished){return false}this.isPaused=true;if(this.previous){this.previous.pause()}return true},resume:function(){if(!this.isPaused||this.isFinished){return false}this.isPaused=false;var e=false;if(this.generatedError){this.error(this.generatedError);e=true}if(this.previous){this.previous.resume()}return!e},flush:function(){},processChunk:function(e){this.push(e)},withStreamInfo:function(e,t){this.extraStreamInfo[e]=t;this.mergeStreamInfo();return this},mergeStreamInfo:function(){for(var e in this.extraStreamInfo){if(!this.extraStreamInfo.hasOwnProperty(e)){continue}this.streamInfo[e]=this.extraStreamInfo[e]}},lock:function(){if(this.isLocked){throw new Error("The stream '"+this+"' has already been used.")}this.isLocked=true;if(this.previous){this.previous.lock()}},toString:function(){var e="Worker "+this.name;if(this.previous){return this.previous+" -> "+e}else{return e}}};t.exports=i},{}],29:[function(e,t,n){"use strict";var r=e("../utils");var s=e("./ConvertWorker");var a=e("./GenericWorker");var i=e("../base64");var o=e("../support");var l=e("../external");var h=null;if(o.nodestream){try{h=e("../nodejs/NodejsStreamOutputAdapter")}catch(e){}}function u(e,t,n){switch(e){case"blob":return r.newBlob(r.transformTo("arraybuffer",t),n);case"base64":return i.encode(t);default:return r.transformTo(e,t)}}function f(e,t){var n,i=0,r=null,s=0;for(n=0;n<t.length;n++){s+=t[n].length}switch(e){case"string":return t.join("");case"array":return Array.prototype.concat.apply([],t);case"uint8array":r=new Uint8Array(s);for(n=0;n<t.length;n++){r.set(t[n],i);i+=t[n].length}return r;case"nodebuffer":return Buffer.concat(t);default:throw new Error("concat : unsupported type '"+e+"'")}}function c(e,o){return new l.Promise(function(t,n){var i=[];var r=e._internalType,s=e._outputType,a=e._mimeType;e.on("data",function(e,t){i.push(e);if(o){o(t)}}).on("error",function(e){i=[];n(e)}).on("end",function(){try{var e=u(s,f(r,i),a);t(e)}catch(e){n(e)}i=[]}).resume()})}function d(e,t,n){var i=t;switch(t){case"blob":case"arraybuffer":i="uint8array";break;case"base64":i="string";break}try{this._internalType=i;this._outputType=t;this._mimeType=n;r.checkSupport(i);this._worker=e.pipe(new s(i));e.lock()}catch(e){this._worker=new a("error");this._worker.error(e)}}d.prototype={accumulate:function(e){return c(this,e)},on:function(e,t){var n=this;if(e==="data"){this._worker.on(e,function(e){t.call(n,e.data,e.meta)})}else{this._worker.on(e,function(){r.delay(t,arguments,n)})}return this},resume:function(){r.delay(this._worker.resume,[],this._worker);return this},pause:function(){this._worker.pause();return this},toNodejsStream:function(e){r.checkSupport("nodestream");if(this._outputType!=="nodebuffer"){throw new Error(this._outputType+" is not supported by this method")}return new h(this,{objectMode:this._outputType!=="nodebuffer"},e)}};t.exports=d},{"../base64":1,"../external":6,"../nodejs/NodejsStreamOutputAdapter":13,"../support":30,"../utils":32,"./ConvertWorker":24,"./GenericWorker":28}],30:[function(e,t,n){"use strict";n.base64=true;n.array=true;n.string=true;n.arraybuffer=typeof ArrayBuffer!=="undefined"&&typeof Uint8Array!=="undefined";n.nodebuffer=typeof Buffer!=="undefined";n.uint8array=typeof Uint8Array!=="undefined";if(typeof ArrayBuffer==="undefined"){n.blob=false}else{var i=new ArrayBuffer(0);try{n.blob=new Blob([i],{type:"application/zip"}).size===0}catch(e){try{var r=self.BlobBuilder||self.WebKitBlobBuilder||self.MozBlobBuilder||self.MSBlobBuilder;var s=new r;s.append(i);n.blob=s.getBlob("application/zip").size===0}catch(e){n.blob=false}}}try{n.nodestream=!!e("readable-stream").Readable}catch(e){n.nodestream=false}},{"readable-stream":16}],31:[function(e,t,s){"use strict";var l=e("./utils");var h=e("./support");var n=e("./nodejsUtils");var i=e("./stream/GenericWorker");var u=new Array(256);for(var r=0;r<256;r++){u[r]=r>=252?6:r>=248?5:r>=240?4:r>=224?3:r>=192?2:1}u[254]=u[254]=1;var a=function(e){var t,n,i,r,s,a=e.length,o=0;for(r=0;r<a;r++){n=e.charCodeAt(r);if((n&64512)===55296&&r+1<a){i=e.charCodeAt(r+1);if((i&64512)===56320){n=65536+(n-55296<<10)+(i-56320);r++}}o+=n<128?1:n<2048?2:n<65536?3:4}if(h.uint8array){t=new Uint8Array(o)}else{t=new Array(o)}for(s=0,r=0;s<o;r++){n=e.charCodeAt(r);if((n&64512)===55296&&r+1<a){i=e.charCodeAt(r+1);if((i&64512)===56320){n=65536+(n-55296<<10)+(i-56320);r++}}if(n<128){t[s++]=n}else if(n<2048){t[s++]=192|n>>>6;t[s++]=128|n&63}else if(n<65536){t[s++]=224|n>>>12;t[s++]=128|n>>>6&63;t[s++]=128|n&63}else{t[s++]=240|n>>>18;t[s++]=128|n>>>12&63;t[s++]=128|n>>>6&63;t[s++]=128|n&63}}return t};var o=function(e,t){var n;t=t||e.length;if(t>e.length){t=e.length}n=t-1;while(n>=0&&(e[n]&192)===128){n--}if(n<0){return t}if(n===0){return t}return n+u[e[n]]>t?n:t};var f=function(e){var t,n,i,r,s;var a=e.length;var o=new Array(a*2);for(i=0,n=0;n<a;){r=e[n++];if(r<128){o[i++]=r;continue}s=u[r];if(s>4){o[i++]=65533;n+=s-1;continue}r&=s===2?31:s===3?15:7;while(s>1&&n<a){r=r<<6|e[n++]&63;s--}if(s>1){o[i++]=65533;continue}if(r<65536){o[i++]=r}else{r-=65536;o[i++]=55296|r>>10&1023;o[i++]=56320|r&1023}}if(o.length!==i){if(o.subarray){o=o.subarray(0,i)}else{o.length=i}}return l.applyFromCharCode(o)};s.utf8encode=function e(t){if(h.nodebuffer){return n.newBufferFrom(t,"utf-8")}return a(t)};s.utf8decode=function e(t){if(h.nodebuffer){return l.transformTo("nodebuffer",t).toString("utf-8")}t=l.transformTo(h.uint8array?"uint8array":"array",t);return f(t)};function c(){i.call(this,"utf-8 decode");this.leftOver=null}l.inherits(c,i);c.prototype.processChunk=function(e){var t=l.transformTo(h.uint8array?"uint8array":"array",e.data);if(this.leftOver&&this.leftOver.length){if(h.uint8array){var n=t;t=new Uint8Array(n.length+this.leftOver.length);t.set(this.leftOver,0);t.set(n,this.leftOver.length)}else{t=this.leftOver.concat(t)}this.leftOver=null}var i=o(t);var r=t;if(i!==t.length){if(h.uint8array){r=t.subarray(0,i);this.leftOver=t.subarray(i,t.length)}else{r=t.slice(0,i);this.leftOver=t.slice(i,t.length)}}this.push({data:s.utf8decode(r),meta:e.meta})};c.prototype.flush=function(){if(this.leftOver&&this.leftOver.length){this.push({data:s.utf8decode(this.leftOver),meta:{}});this.leftOver=null}};s.Utf8DecodeWorker=c;function d(){i.call(this,"utf-8 encode")}l.inherits(d,i);d.prototype.processChunk=function(e){this.push({data:s.utf8encode(e.data),meta:e.meta})};s.Utf8EncodeWorker=d},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(e,t,a){"use strict";var o=e("./support");var l=e("./base64");var n=e("./nodejsUtils");var i=e("set-immediate-shim");var h=e("./external");function u(e){var t=null;if(o.uint8array){t=new Uint8Array(e.length)}else{t=new Array(e.length)}return s(e,t)}a.newBlob=function(t,n){a.checkSupport("blob");try{return new Blob([t],{type:n})}catch(e){try{var i=self.BlobBuilder||self.WebKitBlobBuilder||self.MozBlobBuilder||self.MSBlobBuilder;var r=new i;r.append(t);return r.getBlob(n)}catch(e){throw new Error("Bug : can't construct the Blob.")}}};function r(e){return e}function s(e,t){for(var n=0;n<e.length;++n){t[n]=e.charCodeAt(n)&255}return t}var f={stringifyByChunk:function(e,t,n){var i=[],r=0,s=e.length;if(s<=n){return String.fromCharCode.apply(null,e)}while(r<s){if(t==="array"||t==="nodebuffer"){i.push(String.fromCharCode.apply(null,e.slice(r,Math.min(r+n,s))))}else{i.push(String.fromCharCode.apply(null,e.subarray(r,Math.min(r+n,s))))}r+=n}return i.join("")},stringifyByChar:function(e){var t="";for(var n=0;n<e.length;n++){t+=String.fromCharCode(e[n])}return t},applyCanBeUsed:{uint8array:function(){try{return o.uint8array&&String.fromCharCode.apply(null,new Uint8Array(1)).length===1}catch(e){return false}}(),nodebuffer:function(){try{return o.nodebuffer&&String.fromCharCode.apply(null,n.allocBuffer(1)).length===1}catch(e){return false}}()}};function c(e){var t=65536,n=a.getTypeOf(e),i=true;if(n==="uint8array"){i=f.applyCanBeUsed.uint8array}else if(n==="nodebuffer"){i=f.applyCanBeUsed.nodebuffer}if(i){while(t>1){try{return f.stringifyByChunk(e,n,t)}catch(e){t=Math.floor(t/2)}}}return f.stringifyByChar(e)}a.applyFromCharCode=c;function d(e,t){for(var n=0;n<e.length;n++){t[n]=e[n]}return t}var m={};m["string"]={string:r,array:function(e){return s(e,new Array(e.length))},arraybuffer:function(e){return m["string"]["uint8array"](e).buffer},uint8array:function(e){return s(e,new Uint8Array(e.length))},nodebuffer:function(e){return s(e,n.allocBuffer(e.length))}};m["array"]={string:c,array:r,arraybuffer:function(e){return new Uint8Array(e).buffer},uint8array:function(e){return new Uint8Array(e)},nodebuffer:function(e){return n.newBufferFrom(e)}};m["arraybuffer"]={string:function(e){return c(new Uint8Array(e))},array:function(e){return d(new Uint8Array(e),new Array(e.byteLength))},arraybuffer:r,uint8array:function(e){return new Uint8Array(e)},nodebuffer:function(e){return n.newBufferFrom(new Uint8Array(e))}};m["uint8array"]={string:c,array:function(e){return d(e,new Array(e.length))},arraybuffer:function(e){return e.buffer},uint8array:r,nodebuffer:function(e){return n.newBufferFrom(e)}};m["nodebuffer"]={string:c,array:function(e){return d(e,new Array(e.length))},arraybuffer:function(e){return m["nodebuffer"]["uint8array"](e).buffer},uint8array:function(e){return d(e,new Uint8Array(e.length))},nodebuffer:r};a.transformTo=function(e,t){if(!t){t=""}if(!e){return t}a.checkSupport(e);var n=a.getTypeOf(t);var i=m[n][e](t);return i};a.getTypeOf=function(e){if(typeof e==="string"){return"string"}if(Object.prototype.toString.call(e)==="[object Array]"){return"array"}if(o.nodebuffer&&n.isBuffer(e)){return"nodebuffer"}if(o.uint8array&&e instanceof Uint8Array){return"uint8array"}if(o.arraybuffer&&e instanceof ArrayBuffer){return"arraybuffer"}};a.checkSupport=function(e){var t=o[e.toLowerCase()];if(!t){throw new Error(e+" is not supported by this platform")}};a.MAX_VALUE_16BITS=65535;a.MAX_VALUE_32BITS=-1;a.pretty=function(e){var t="",n,i;for(i=0;i<(e||"").length;i++){n=e.charCodeAt(i);t+="\\x"+(n<16?"0":"")+n.toString(16).toUpperCase()}return t};a.delay=function(e,t,n){i(function(){e.apply(n||null,t||[])})};a.inherits=function(e,t){var n=function(){};n.prototype=t.prototype;e.prototype=new n};a.extend=function(){var e={},t,n;for(t=0;t<arguments.length;t++){for(n in arguments[t]){if(arguments[t].hasOwnProperty(n)&&typeof e[n]==="undefined"){e[n]=arguments[t][n]}}}return e};a.prepareContent=function(n,e,i,r,s){var t=h.Promise.resolve(e).then(function(i){var e=o.blob&&(i instanceof Blob||["[object File]","[object Blob]"].indexOf(Object.prototype.toString.call(i))!==-1);if(e&&typeof FileReader!=="undefined"){return new h.Promise(function(t,n){var e=new FileReader;e.onload=function(e){t(e.target.result)};e.onerror=function(e){n(e.target.error)};e.readAsArrayBuffer(i)})}else{return i}});return t.then(function(e){var t=a.getTypeOf(e);if(!t){return h.Promise.reject(new Error("Can't read the data of '"+n+"'. Is it "+"in a supported JavaScript type (String, Blob, ArrayBuffer, etc) ?"))}if(t==="arraybuffer"){e=a.transformTo("uint8array",e)}else if(t==="string"){if(s){e=l.decode(e)}else if(i){if(r!==true){e=u(e)}}}return e})}},{"./base64":1,"./external":6,"./nodejsUtils":14,"./support":30,"set-immediate-shim":54}],33:[function(e,t,n){"use strict";var i=e("./reader/readerFor");var s=e("./utils");var a=e("./signature");var r=e("./zipEntry");var o=e("./utf8");var l=e("./support");function h(e){this.files=[];this.loadOptions=e}h.prototype={checkSignature:function(e){if(!this.reader.readAndCheckSignature(e)){this.reader.index-=4;var t=this.reader.readString(4);throw new Error("Corrupted zip or bug: unexpected signature "+"("+s.pretty(t)+", expected "+s.pretty(e)+")")}},isSignature:function(e,t){var n=this.reader.index;this.reader.setIndex(e);var i=this.reader.readString(4);var r=i===t;this.reader.setIndex(n);return r},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2);this.diskWithCentralDirStart=this.reader.readInt(2);this.centralDirRecordsOnThisDisk=this.reader.readInt(2);this.centralDirRecords=this.reader.readInt(2);this.centralDirSize=this.reader.readInt(4);this.centralDirOffset=this.reader.readInt(4);this.zipCommentLength=this.reader.readInt(2);var e=this.reader.readData(this.zipCommentLength);var t=l.uint8array?"uint8array":"array";var n=s.transformTo(t,e);this.zipComment=this.loadOptions.decodeFileName(n)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8);this.reader.skip(4);this.diskNumber=this.reader.readInt(4);this.diskWithCentralDirStart=this.reader.readInt(4);this.centralDirRecordsOnThisDisk=this.reader.readInt(8);this.centralDirRecords=this.reader.readInt(8);this.centralDirSize=this.reader.readInt(8);this.centralDirOffset=this.reader.readInt(8);this.zip64ExtensibleData={};var e=this.zip64EndOfCentralSize-44,t=0,n,i,r;while(t<e){n=this.reader.readInt(2);i=this.reader.readInt(4);r=this.reader.readData(i);this.zip64ExtensibleData[n]={id:n,length:i,value:r}}},readBlockZip64EndOfCentralLocator:function(){this.diskWithZip64CentralDirStart=this.reader.readInt(4);this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8);this.disksCount=this.reader.readInt(4);if(this.disksCount>1){throw new Error("Multi-volumes zip are not supported")}},readLocalFiles:function(){var e,t;for(e=0;e<this.files.length;e++){t=this.files[e];this.reader.setIndex(t.localHeaderOffset);this.checkSignature(a.LOCAL_FILE_HEADER);t.readLocalPart(this.reader);t.handleUTF8();t.processAttributes()}},readCentralDir:function(){var e;this.reader.setIndex(this.centralDirOffset);while(this.reader.readAndCheckSignature(a.CENTRAL_FILE_HEADER)){e=new r({zip64:this.zip64},this.loadOptions);e.readCentralPart(this.reader);this.files.push(e)}if(this.centralDirRecords!==this.files.length){if(this.centralDirRecords!==0&&this.files.length===0){throw new Error("Corrupted zip or bug: expected "+this.centralDirRecords+" records in central dir, got "+this.files.length)}else{}}},readEndOfCentral:function(){var e=this.reader.lastIndexOfSignature(a.CENTRAL_DIRECTORY_END);if(e<0){var t=!this.isSignature(0,a.LOCAL_FILE_HEADER);if(t){throw new Error("Can't find end of central directory : is this a zip file ? "+"If it is, see https://stuk.github.io/jszip/documentation/howto/read_zip.html")}else{throw new Error("Corrupted zip: can't find end of central directory")}}this.reader.setIndex(e);var n=e;this.checkSignature(a.CENTRAL_DIRECTORY_END);this.readBlockEndOfCentral();if(this.diskNumber===s.MAX_VALUE_16BITS||this.diskWithCentralDirStart===s.MAX_VALUE_16BITS||this.centralDirRecordsOnThisDisk===s.MAX_VALUE_16BITS||this.centralDirRecords===s.MAX_VALUE_16BITS||this.centralDirSize===s.MAX_VALUE_32BITS||this.centralDirOffset===s.MAX_VALUE_32BITS){this.zip64=true;e=this.reader.lastIndexOfSignature(a.ZIP64_CENTRAL_DIRECTORY_LOCATOR);if(e<0){throw new Error("Corrupted zip: can't find the ZIP64 end of central directory locator")}this.reader.setIndex(e);this.checkSignature(a.ZIP64_CENTRAL_DIRECTORY_LOCATOR);this.readBlockZip64EndOfCentralLocator();if(!this.isSignature(this.relativeOffsetEndOfZip64CentralDir,a.ZIP64_CENTRAL_DIRECTORY_END)){this.relativeOffsetEndOfZip64CentralDir=this.reader.lastIndexOfSignature(a.ZIP64_CENTRAL_DIRECTORY_END);if(this.relativeOffsetEndOfZip64CentralDir<0){throw new Error("Corrupted zip: can't find the ZIP64 end of central directory")}}this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir);this.checkSignature(a.ZIP64_CENTRAL_DIRECTORY_END);this.readBlockZip64EndOfCentral()}var i=this.centralDirOffset+this.centralDirSize;if(this.zip64){i+=20;i+=12+this.zip64EndOfCentralSize}var r=n-i;if(r>0){if(this.isSignature(n,a.CENTRAL_FILE_HEADER)){}else{this.reader.zero=r}}else if(r<0){throw new Error("Corrupted zip: missing "+Math.abs(r)+" bytes.")}},prepareReader:function(e){this.reader=i(e)},load:function(e){this.prepareReader(e);this.readEndOfCentral();this.readCentralDir();this.readLocalFiles()}};t.exports=h},{"./reader/readerFor":22,"./signature":23,"./support":30,"./utf8":31,"./utils":32,"./zipEntry":34}],34:[function(e,t,n){"use strict";var i=e("./reader/readerFor");var s=e("./utils");var r=e("./compressedObject");var a=e("./crc32");var o=e("./utf8");var l=e("./compressions");var h=e("./support");var u=0;var f=3;var c=function(e){for(var t in l){if(!l.hasOwnProperty(t)){continue}if(l[t].magic===e){return l[t]}}return null};function d(e,t){this.options=e;this.loadOptions=t}d.prototype={isEncrypted:function(){return(this.bitFlag&1)===1},useUTF8:function(){return(this.bitFlag&2048)===2048},readLocalPart:function(e){var t,n;e.skip(22);this.fileNameLength=e.readInt(2);n=e.readInt(2);this.fileName=e.readData(this.fileNameLength);e.skip(n);if(this.compressedSize===-1||this.uncompressedSize===-1){throw new Error("Bug or corrupted zip : didn't get enough information from the central directory "+"(compressedSize === -1 || uncompressedSize === -1)")}t=c(this.compressionMethod);if(t===null){throw new Error("Corrupted zip : compression "+s.pretty(this.compressionMethod)+" unknown (inner file : "+s.transformTo("string",this.fileName)+")")}this.decompressed=new r(this.compressedSize,this.uncompressedSize,this.crc32,t,e.readData(this.compressedSize))},readCentralPart:function(e){this.versionMadeBy=e.readInt(2);e.skip(2);this.bitFlag=e.readInt(2);this.compressionMethod=e.readString(2);this.date=e.readDate();this.crc32=e.readInt(4);this.compressedSize=e.readInt(4);this.uncompressedSize=e.readInt(4);var t=e.readInt(2);this.extraFieldsLength=e.readInt(2);this.fileCommentLength=e.readInt(2);this.diskNumberStart=e.readInt(2);this.internalFileAttributes=e.readInt(2);this.externalFileAttributes=e.readInt(4);this.localHeaderOffset=e.readInt(4);if(this.isEncrypted()){throw new Error("Encrypted zip are not supported")}e.skip(t);this.readExtraFields(e);this.parseZIP64ExtraField(e);this.fileComment=e.readData(this.fileCommentLength)},processAttributes:function(){this.unixPermissions=null;this.dosPermissions=null;var e=this.versionMadeBy>>8;this.dir=this.externalFileAttributes&16?true:false;if(e===u){this.dosPermissions=this.externalFileAttributes&63}if(e===f){this.unixPermissions=this.externalFileAttributes>>16&65535}if(!this.dir&&this.fileNameStr.slice(-1)==="/"){this.dir=true}},parseZIP64ExtraField:function(e){if(!this.extraFields[1]){return}var t=i(this.extraFields[1].value);if(this.uncompressedSize===s.MAX_VALUE_32BITS){this.uncompressedSize=t.readInt(8)}if(this.compressedSize===s.MAX_VALUE_32BITS){this.compressedSize=t.readInt(8)}if(this.localHeaderOffset===s.MAX_VALUE_32BITS){this.localHeaderOffset=t.readInt(8)}if(this.diskNumberStart===s.MAX_VALUE_32BITS){this.diskNumberStart=t.readInt(4)}},readExtraFields:function(e){var t=e.index+this.extraFieldsLength,n,i,r;if(!this.extraFields){this.extraFields={}}while(e.index+4<t){n=e.readInt(2);i=e.readInt(2);r=e.readData(i);this.extraFields[n]={id:n,length:i,value:r}}e.setIndex(t)},handleUTF8:function(){var e=h.uint8array?"uint8array":"array";if(this.useUTF8()){this.fileNameStr=o.utf8decode(this.fileName);this.fileCommentStr=o.utf8decode(this.fileComment)}else{var t=this.findExtraFieldUnicodePath();if(t!==null){this.fileNameStr=t}else{var n=s.transformTo(e,this.fileName);this.fileNameStr=this.loadOptions.decodeFileName(n)}var i=this.findExtraFieldUnicodeComment();if(i!==null){this.fileCommentStr=i}else{var r=s.transformTo(e,this.fileComment);this.fileCommentStr=this.loadOptions.decodeFileName(r)}}},findExtraFieldUnicodePath:function(){var e=this.extraFields[28789];if(e){var t=i(e.value);if(t.readInt(1)!==1){return null}if(a(this.fileName)!==t.readInt(4)){return null}return o.utf8decode(t.readData(e.length-5))}return null},findExtraFieldUnicodeComment:function(){var e=this.extraFields[25461];if(e){var t=i(e.value);if(t.readInt(1)!==1){return null}if(a(this.fileComment)!==t.readInt(4)){return null}return o.utf8decode(t.readData(e.length-5))}return null}};t.exports=d},{"./compressedObject":2,"./compressions":3,"./crc32":4,"./reader/readerFor":22,"./support":30,"./utf8":31,"./utils":32}],35:[function(e,t,n){"use strict";var s=e("./stream/StreamHelper");var i=e("./stream/DataWorker");var a=e("./utf8");var r=e("./compressedObject");var o=e("./stream/GenericWorker");var l=function(e,t,n){this.name=e;this.dir=n.dir;this.date=n.date;this.comment=n.comment;this.unixPermissions=n.unixPermissions;this.dosPermissions=n.dosPermissions;this._data=t;this._dataBinary=n.binary;this.options={compression:n.compression,compressionOptions:n.compressionOptions}};l.prototype={internalStream:function(e){var t=null,n="string";try{if(!e){throw new Error("No output type specified.")}n=e.toLowerCase();var i=n==="string"||n==="text";if(n==="binarystring"||n==="text"){n="string"}t=this._decompressWorker();var r=!this._dataBinary;if(r&&!i){t=t.pipe(new a.Utf8EncodeWorker)}if(!r&&i){t=t.pipe(new a.Utf8DecodeWorker)}}catch(e){t=new o("error");t.error(e)}return new s(t,n,"")},async:function(e,t){return this.internalStream(e).accumulate(t)},nodeStream:function(e,t){return this.internalStream(e||"nodebuffer").toNodejsStream(t)},_compressWorker:function(e,t){if(this._data instanceof r&&this._data.compression.magic===e.magic){return this._data.getCompressedWorker()}else{var n=this._decompressWorker();if(!this._dataBinary){n=n.pipe(new a.Utf8EncodeWorker)}return r.createWorkerFrom(n,e,t)}},_decompressWorker:function(){if(this._data instanceof r){return this._data.getContentWorker()}else if(this._data instanceof o){return this._data}else{return new i(this._data)}}};var h=["asText","asBinary","asNodeBuffer","asUint8Array","asArrayBuffer"];var u=function(){throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.")};for(var f=0;f<h.length;f++){l.prototype[h[f]]=u}t.exports=l},{"./compressedObject":2,"./stream/DataWorker":27,"./stream/GenericWorker":28,"./stream/StreamHelper":29,"./utf8":31}],36:[function(e,f,t){(function(t){"use strict";var e=t.MutationObserver||t.WebKitMutationObserver;var n;{if(e){var i=0;var r=new e(h);var s=t.document.createTextNode("");r.observe(s,{characterData:true});n=function(){s.data=i=++i%2}}else if(!t.setImmediate&&typeof t.MessageChannel!=="undefined"){var a=new t.MessageChannel;a.port1.onmessage=h;n=function(){a.port2.postMessage(0)}}else if("document"in t&&"onreadystatechange"in t.document.createElement("script")){n=function(){var e=t.document.createElement("script");e.onreadystatechange=function(){h();e.onreadystatechange=null;e.parentNode.removeChild(e);e=null};t.document.documentElement.appendChild(e)}}else{n=function(){setTimeout(h,0)}}}var o;var l=[];function h(){o=true;var e,t;var n=l.length;while(n){t=l;l=[];e=-1;while(++e<n){t[e]()}n=l.length}o=false}f.exports=u;function u(e){if(l.push(e)===1&&!o){n()}}}).call(this,typeof global!=="undefined"?global:typeof self!=="undefined"?self:typeof window!=="undefined"?window:{})},{}],37:[function(e,t,n){"use strict";var r=e("immediate");function h(){}var u={};var s=["REJECTED"];var a=["FULFILLED"];var o=["PENDING"];t.exports=i;function i(e){if(typeof e!=="function"){throw new TypeError("resolver must be a function")}this.state=o;this.queue=[];this.outcome=void 0;if(e!==h){d(this,e)}}i.prototype["finally"]=function(n){if(typeof n!=="function"){return this}var i=this.constructor;return this.then(e,t);function e(e){function t(){return e}return i.resolve(n()).then(t)}function t(e){function t(){throw e}return i.resolve(n()).then(t)}};i.prototype["catch"]=function(e){return this.then(null,e)};i.prototype.then=function(e,t){if(typeof e!=="function"&&this.state===a||typeof t!=="function"&&this.state===s){return this}var n=new this.constructor(h);if(this.state!==o){var i=this.state===a?e:t;f(n,i,this.outcome)}else{this.queue.push(new l(n,e,t))}return n};function l(e,t,n){this.promise=e;if(typeof t==="function"){this.onFulfilled=t;this.callFulfilled=this.otherCallFulfilled}if(typeof n==="function"){this.onRejected=n;this.callRejected=this.otherCallRejected}}l.prototype.callFulfilled=function(e){u.resolve(this.promise,e)};l.prototype.otherCallFulfilled=function(e){f(this.promise,this.onFulfilled,e)};l.prototype.callRejected=function(e){u.reject(this.promise,e)};l.prototype.otherCallRejected=function(e){f(this.promise,this.onRejected,e)};function f(t,n,i){r(function(){var e;try{e=n(i)}catch(e){return u.reject(t,e)}if(e===t){u.reject(t,new TypeError("Cannot resolve promise with itself"))}else{u.resolve(t,e)}})}u.resolve=function(e,t){var n=m(c,t);if(n.status==="error"){return u.reject(e,n.value)}var i=n.value;if(i){d(e,i)}else{e.state=a;e.outcome=t;var r=-1;var s=e.queue.length;while(++r<s){e.queue[r].callFulfilled(t)}}return e};u.reject=function(e,t){e.state=s;e.outcome=t;var n=-1;var i=e.queue.length;while(++n<i){e.queue[n].callRejected(t)}return e};function c(t){var n=t&&t.then;if(t&&(typeof t==="object"||typeof t==="function")&&typeof n==="function"){return function e(){n.apply(t,arguments)}}}function d(t,e){var n=false;function i(e){if(n){return}n=true;u.reject(t,e)}function r(e){if(n){return}n=true;u.resolve(t,e)}function s(){e(r,i)}var a=m(s);if(a.status==="error"){i(a.value)}}function m(e,t){var n={};try{n.value=e(t);n.status="success"}catch(e){n.status="error";n.value=e}return n}i.resolve=g;function g(e){if(e instanceof this){return e}return u.resolve(new this(h),e)}i.reject=p;function p(e){var t=new this(h);return u.reject(t,e)}i.all=F;function F(e){var i=this;if(Object.prototype.toString.call(e)!=="[object Array]"){return this.reject(new TypeError("must be an array"))}var r=e.length;var s=false;if(!r){return this.resolve([])}var a=new Array(r);var o=0;var t=-1;var l=new this(h);while(++t<r){n(e[t],t)}return l;function n(e,t){i.resolve(e).then(n,function(e){if(!s){s=true;u.reject(l,e)}});function n(e){a[t]=e;if(++o===r&&!s){s=true;u.resolve(l,a)}}}}i.race=A;function A(e){var t=this;if(Object.prototype.toString.call(e)!=="[object Array]"){return this.reject(new TypeError("must be an array"))}var n=e.length;var i=false;if(!n){return this.resolve([])}var r=-1;var s=new this(h);while(++r<n){a(e[r])}return s;function a(e){t.resolve(e).then(function(e){if(!i){i=true;u.resolve(s,e)}},function(e){if(!i){i=true;u.reject(s,e)}})}}},{immediate:36}],38:[function(e,t,n){"use strict";var i=e("./lib/utils/common").assign;var r=e("./lib/deflate");var s=e("./lib/inflate");var a=e("./lib/zlib/constants");var o={};i(o,r,s,a);t.exports=o},{"./lib/deflate":39,"./lib/inflate":40,"./lib/utils/common":41,"./lib/zlib/constants":44}],39:[function(e,t,n){"use strict";var a=e("./zlib/deflate");var o=e("./utils/common");var l=e("./utils/strings");var r=e("./zlib/messages");var s=e("./zlib/zstream");var h=Object.prototype.toString;var u=0;var f=4;var c=0;var d=1;var m=2;var g=-1;var p=0;var F=8;function A(e){if(!(this instanceof A))return new A(e);this.options=o.assign({level:g,method:F,chunkSize:16384,windowBits:15,memLevel:8,strategy:p,to:""},e||{});var t=this.options;if(t.raw&&t.windowBits>0){t.windowBits=-t.windowBits}else if(t.gzip&&t.windowBits>0&&t.windowBits<16){t.windowBits+=16}this.err=0;this.msg="";this.ended=false;this.chunks=[];this.strm=new s;this.strm.avail_out=0;var n=a.deflateInit2(this.strm,t.level,t.method,t.windowBits,t.memLevel,t.strategy);if(n!==c){throw new Error(r[n])}if(t.header){a.deflateSetHeader(this.strm,t.header)}if(t.dictionary){var i;if(typeof t.dictionary==="string"){i=l.string2buf(t.dictionary)}else if(h.call(t.dictionary)==="[object ArrayBuffer]"){i=new Uint8Array(t.dictionary)}else{i=t.dictionary}n=a.deflateSetDictionary(this.strm,i);if(n!==c){throw new Error(r[n])}this._dict_set=true}}A.prototype.push=function(e,t){var n=this.strm;var i=this.options.chunkSize;var r,s;if(this.ended){return false}s=t===~~t?t:t===true?f:u;if(typeof e==="string"){n.input=l.string2buf(e)}else if(h.call(e)==="[object ArrayBuffer]"){n.input=new Uint8Array(e)}else{n.input=e}n.next_in=0;n.avail_in=n.input.length;do{if(n.avail_out===0){n.output=new o.Buf8(i);n.next_out=0;n.avail_out=i}r=a.deflate(n,s);if(r!==d&&r!==c){this.onEnd(r);this.ended=true;return false}if(n.avail_out===0||n.avail_in===0&&(s===f||s===m)){if(this.options.to==="string"){this.onData(l.buf2binstring(o.shrinkBuf(n.output,n.next_out)))}else{this.onData(o.shrinkBuf(n.output,n.next_out))}}}while((n.avail_in>0||n.avail_out===0)&&r!==d);if(s===f){r=a.deflateEnd(this.strm);this.onEnd(r);this.ended=true;return r===c}if(s===m){this.onEnd(c);n.avail_out=0;return true}return true};A.prototype.onData=function(e){this.chunks.push(e)};A.prototype.onEnd=function(e){if(e===c){if(this.options.to==="string"){this.result=this.chunks.join("")}else{this.result=o.flattenChunks(this.chunks)}}this.chunks=[];this.err=e;this.msg=this.strm.msg};function i(e,t){var n=new A(t);n.push(e,true);if(n.err){throw n.msg||r[n.err]}return n.result}function C(e,t){t=t||{};t.raw=true;return i(e,t)}function _(e,t){t=t||{};t.gzip=true;return i(e,t)}n.Deflate=A;n.deflate=i;n.deflateRaw=C;n.gzip=_},{"./utils/common":41,"./utils/strings":42,"./zlib/deflate":46,"./zlib/messages":51,"./zlib/zstream":53}],40:[function(e,t,n){"use strict";var c=e("./zlib/inflate");var d=e("./utils/common");var m=e("./utils/strings");var g=e("./zlib/constants");var i=e("./zlib/messages");var r=e("./zlib/zstream");var s=e("./zlib/gzheader");var p=Object.prototype.toString;function a(e){if(!(this instanceof a))return new a(e);this.options=d.assign({chunkSize:16384,windowBits:0,to:""},e||{});var t=this.options;if(t.raw&&t.windowBits>=0&&t.windowBits<16){t.windowBits=-t.windowBits;if(t.windowBits===0){t.windowBits=-15}}if(t.windowBits>=0&&t.windowBits<16&&!(e&&e.windowBits)){t.windowBits+=32}if(t.windowBits>15&&t.windowBits<48){if((t.windowBits&15)===0){t.windowBits|=15}}this.err=0;this.msg="";this.ended=false;this.chunks=[];this.strm=new r;this.strm.avail_out=0;var n=c.inflateInit2(this.strm,t.windowBits);if(n!==g.Z_OK){throw new Error(i[n])}this.header=new s;c.inflateGetHeader(this.strm,this.header)}a.prototype.push=function(e,t){var n=this.strm;var i=this.options.chunkSize;var r=this.options.dictionary;var s,a;var o,l,h;var u;var f=false;if(this.ended){return false}a=t===~~t?t:t===true?g.Z_FINISH:g.Z_NO_FLUSH;if(typeof e==="string"){n.input=m.binstring2buf(e)}else if(p.call(e)==="[object ArrayBuffer]"){n.input=new Uint8Array(e)}else{n.input=e}n.next_in=0;n.avail_in=n.input.length;do{if(n.avail_out===0){n.output=new d.Buf8(i);n.next_out=0;n.avail_out=i}s=c.inflate(n,g.Z_NO_FLUSH);if(s===g.Z_NEED_DICT&&r){if(typeof r==="string"){u=m.string2buf(r)}else if(p.call(r)==="[object ArrayBuffer]"){u=new Uint8Array(r)}else{u=r}s=c.inflateSetDictionary(this.strm,u)}if(s===g.Z_BUF_ERROR&&f===true){s=g.Z_OK;f=false}if(s!==g.Z_STREAM_END&&s!==g.Z_OK){this.onEnd(s);this.ended=true;return false}if(n.next_out){if(n.avail_out===0||s===g.Z_STREAM_END||n.avail_in===0&&(a===g.Z_FINISH||a===g.Z_SYNC_FLUSH)){if(this.options.to==="string"){o=m.utf8border(n.output,n.next_out);l=n.next_out-o;h=m.buf2string(n.output,o);n.next_out=l;n.avail_out=i-l;if(l){d.arraySet(n.output,n.output,o,l,0)}this.onData(h)}else{this.onData(d.shrinkBuf(n.output,n.next_out))}}}if(n.avail_in===0&&n.avail_out===0){f=true}}while((n.avail_in>0||n.avail_out===0)&&s!==g.Z_STREAM_END);if(s===g.Z_STREAM_END){a=g.Z_FINISH}if(a===g.Z_FINISH){s=c.inflateEnd(this.strm);this.onEnd(s);this.ended=true;return s===g.Z_OK}if(a===g.Z_SYNC_FLUSH){this.onEnd(g.Z_OK);n.avail_out=0;return true}return true};a.prototype.onData=function(e){this.chunks.push(e)};a.prototype.onEnd=function(e){if(e===g.Z_OK){if(this.options.to==="string"){this.result=this.chunks.join("")}else{this.result=d.flattenChunks(this.chunks)}}this.chunks=[];this.err=e;this.msg=this.strm.msg};function o(e,t){var n=new a(t);n.push(e,true);if(n.err){throw n.msg||i[n.err]}return n.result}function l(e,t){t=t||{};t.raw=true;return o(e,t)}n.Inflate=a;n.inflate=o;n.inflateRaw=l;n.ungzip=o},{"./utils/common":41,"./utils/strings":42,"./zlib/constants":44,"./zlib/gzheader":47,"./zlib/inflate":49,"./zlib/messages":51,"./zlib/zstream":53}],41:[function(e,t,n){"use strict";var i=typeof Uint8Array!=="undefined"&&typeof Uint16Array!=="undefined"&&typeof Int32Array!=="undefined";n.assign=function(e){var t=Array.prototype.slice.call(arguments,1);while(t.length){var n=t.shift();if(!n){continue}if(typeof n!=="object"){throw new TypeError(n+"must be non-object")}for(var i in n){if(n.hasOwnProperty(i)){e[i]=n[i]}}}return e};n.shrinkBuf=function(e,t){if(e.length===t){return e}if(e.subarray){return e.subarray(0,t)}e.length=t;return e};var r={arraySet:function(e,t,n,i,r){if(t.subarray&&e.subarray){e.set(t.subarray(n,n+i),r);return}for(var s=0;s<i;s++){e[r+s]=t[n+s]}},flattenChunks:function(e){var t,n,i,r,s,a;i=0;for(t=0,n=e.length;t<n;t++){i+=e[t].length}a=new Uint8Array(i);r=0;for(t=0,n=e.length;t<n;t++){s=e[t];a.set(s,r);r+=s.length}return a}};var s={arraySet:function(e,t,n,i,r){for(var s=0;s<i;s++){e[r+s]=t[n+s]}},flattenChunks:function(e){return[].concat.apply([],e)}};n.setTyped=function(e){if(e){n.Buf8=Uint8Array;n.Buf16=Uint16Array;n.Buf32=Int32Array;n.assign(n,r)}else{n.Buf8=Array;n.Buf16=Array;n.Buf32=Array;n.assign(n,s)}};n.setTyped(i)},{}],42:[function(e,t,n){"use strict";var l=e("./common");var r=true;var s=true;try{String.fromCharCode.apply(null,[0])}catch(e){r=false}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(e){s=false}var h=new l.Buf8(256);for(var i=0;i<256;i++){h[i]=i>=252?6:i>=248?5:i>=240?4:i>=224?3:i>=192?2:1}h[254]=h[254]=1;n.string2buf=function(e){var t,n,i,r,s,a=e.length,o=0;for(r=0;r<a;r++){n=e.charCodeAt(r);if((n&64512)===55296&&r+1<a){i=e.charCodeAt(r+1);if((i&64512)===56320){n=65536+(n-55296<<10)+(i-56320);r++}}o+=n<128?1:n<2048?2:n<65536?3:4}t=new l.Buf8(o);for(s=0,r=0;s<o;r++){n=e.charCodeAt(r);if((n&64512)===55296&&r+1<a){i=e.charCodeAt(r+1);if((i&64512)===56320){n=65536+(n-55296<<10)+(i-56320);r++}}if(n<128){t[s++]=n}else if(n<2048){t[s++]=192|n>>>6;t[s++]=128|n&63}else if(n<65536){t[s++]=224|n>>>12;t[s++]=128|n>>>6&63;t[s++]=128|n&63}else{t[s++]=240|n>>>18;t[s++]=128|n>>>12&63;t[s++]=128|n>>>6&63;t[s++]=128|n&63}}return t};function u(e,t){if(t<65537){if(e.subarray&&s||!e.subarray&&r){return String.fromCharCode.apply(null,l.shrinkBuf(e,t))}}var n="";for(var i=0;i<t;i++){n+=String.fromCharCode(e[i])}return n}n.buf2binstring=function(e){return u(e,e.length)};n.binstring2buf=function(e){var t=new l.Buf8(e.length);for(var n=0,i=t.length;n<i;n++){t[n]=e.charCodeAt(n)}return t};n.buf2string=function(e,t){var n,i,r,s;var a=t||e.length;var o=new Array(a*2);for(i=0,n=0;n<a;){r=e[n++];if(r<128){o[i++]=r;continue}s=h[r];if(s>4){o[i++]=65533;n+=s-1;continue}r&=s===2?31:s===3?15:7;while(s>1&&n<a){r=r<<6|e[n++]&63;s--}if(s>1){o[i++]=65533;continue}if(r<65536){o[i++]=r}else{r-=65536;o[i++]=55296|r>>10&1023;o[i++]=56320|r&1023}}return u(o,i)};n.utf8border=function(e,t){var n;t=t||e.length;if(t>e.length){t=e.length}n=t-1;while(n>=0&&(e[n]&192)===128){n--}if(n<0){return t}if(n===0){return t}return n+h[e[n]]>t?n:t}},{"./common":41}],43:[function(e,t,n){"use strict";function i(e,t,n,i){var r=e&65535|0,s=e>>>16&65535|0,a=0;while(n!==0){a=n>2e3?2e3:n;n-=a;do{r=r+t[i++]|0;s=s+r|0}while(--a);r%=65521;s%=65521}return r|s<<16|0}t.exports=i},{}],44:[function(e,t,n){"use strict";t.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],45:[function(e,t,n){"use strict";function i(){var e,t=[];for(var n=0;n<256;n++){e=n;for(var i=0;i<8;i++){e=e&1?3988292384^e>>>1:e>>>1}t[n]=e}return t}var o=i();function r(e,t,n,i){var r=o,s=i+n;e^=-1;for(var a=i;a<s;a++){e=e>>>8^r[(e^t[a])&255]}return e^-1}t.exports=r},{}],46:[function(e,s,t){"use strict";var f=e("../utils/common");var h=e("./trees");var U=e("./adler32");var u=e("./crc32");var a=e("./messages");var c=0;var V=1;var G=3;var d=4;var j=5;var m=0;var z=1;var g=-2;var l=-3;var p=-5;var X=-1;var H=1;var F=2;var W=3;var Y=4;var Z=0;var K=2;var A=8;var Q=9;var q=15;var J=8;var $=29;var ee=256;var n=ee+1+$;var te=30;var ne=19;var ie=2*n+1;var re=15;var C=3;var _=258;var E=_+C+1;var se=32;var v=42;var ae=69;var b=73;var B=91;var D=103;var y=113;var x=666;var S=1;var T=2;var O=3;var I=4;var oe=3;function w(e,t){e.msg=a[t];return t}function le(e){return(e<<1)-(e>4?9:0)}function L(e){var t=e.length;while(--t>=0){e[t]=0}}function N(e){var t=e.state;var n=t.pending;if(n>e.avail_out){n=e.avail_out}if(n===0){return}f.arraySet(e.output,t.pending_buf,t.pending_out,n,e.next_out);e.next_out+=n;t.pending_out+=n;e.total_out+=n;e.avail_out-=n;t.pending-=n;if(t.pending===0){t.pending_out=0}}function o(e,t){h._tr_flush_block(e,e.block_start>=0?e.block_start:-1,e.strstart-e.block_start,t);e.block_start=e.strstart;N(e.strm)}function R(e,t){e.pending_buf[e.pending++]=t}function k(e,t){e.pending_buf[e.pending++]=t>>>8&255;e.pending_buf[e.pending++]=t&255}function he(e,t,n,i){var r=e.avail_in;if(r>i){r=i}if(r===0){return 0}e.avail_in-=r;f.arraySet(t,e.input,e.next_in,r,n);if(e.state.wrap===1){e.adler=U(e.adler,t,r,n)}else if(e.state.wrap===2){e.adler=u(e.adler,t,r,n)}e.next_in+=r;e.total_in+=r;return r}function ue(e,t){var n=e.max_chain_length;var i=e.strstart;var r;var s;var a=e.prev_length;var o=e.nice_match;var l=e.strstart>e.w_size-E?e.strstart-(e.w_size-E):0;var h=e.window;var u=e.w_mask;var f=e.prev;var c=e.strstart+_;var d=h[i+a-1];var m=h[i+a];if(e.prev_length>=e.good_match){n>>=2}if(o>e.lookahead){o=e.lookahead}do{r=t;if(h[r+a]!==m||h[r+a-1]!==d||h[r]!==h[i]||h[++r]!==h[i+1]){continue}i+=2;r++;do{}while(h[++i]===h[++r]&&h[++i]===h[++r]&&h[++i]===h[++r]&&h[++i]===h[++r]&&h[++i]===h[++r]&&h[++i]===h[++r]&&h[++i]===h[++r]&&h[++i]===h[++r]&&i<c);s=_-(c-i);i=c-_;if(s>a){e.match_start=t;a=s;if(s>=o){break}d=h[i+a-1];m=h[i+a]}}while((t=f[t&u])>l&&--n!==0);if(a<=e.lookahead){return a}return e.lookahead}function M(e){var t=e.w_size;var n,i,r,s,a;do{s=e.window_size-e.lookahead-e.strstart;if(e.strstart>=t+(t-E)){f.arraySet(e.window,e.window,t,t,0);e.match_start-=t;e.strstart-=t;e.block_start-=t;i=e.hash_size;n=i;do{r=e.head[--n];e.head[n]=r>=t?r-t:0}while(--i);i=t;n=i;do{r=e.prev[--n];e.prev[n]=r>=t?r-t:0}while(--i);s+=t}if(e.strm.avail_in===0){break}i=he(e.strm,e.window,e.strstart+e.lookahead,s);e.lookahead+=i;if(e.lookahead+e.insert>=C){a=e.strstart-e.insert;e.ins_h=e.window[a];e.ins_h=(e.ins_h<<e.hash_shift^e.window[a+1])&e.hash_mask;while(e.insert){e.ins_h=(e.ins_h<<e.hash_shift^e.window[a+C-1])&e.hash_mask;e.prev[a&e.w_mask]=e.head[e.ins_h];e.head[e.ins_h]=a;a++;e.insert--;if(e.lookahead+e.insert<C){break}}}}while(e.lookahead<E&&e.strm.avail_in!==0)}function fe(e,t){var n=65535;if(n>e.pending_buf_size-5){n=e.pending_buf_size-5}for(;;){if(e.lookahead<=1){M(e);if(e.lookahead===0&&t===c){return S}if(e.lookahead===0){break}}e.strstart+=e.lookahead;e.lookahead=0;var i=e.block_start+n;if(e.strstart===0||e.strstart>=i){e.lookahead=e.strstart-i;e.strstart=i;o(e,false);if(e.strm.avail_out===0){return S}}if(e.strstart-e.block_start>=e.w_size-E){o(e,false);if(e.strm.avail_out===0){return S}}}e.insert=0;if(t===d){o(e,true);if(e.strm.avail_out===0){return O}return I}if(e.strstart>e.block_start){o(e,false);if(e.strm.avail_out===0){return S}}return S}function ce(e,t){var n;var i;for(;;){if(e.lookahead<E){M(e);if(e.lookahead<E&&t===c){return S}if(e.lookahead===0){break}}n=0;if(e.lookahead>=C){e.ins_h=(e.ins_h<<e.hash_shift^e.window[e.strstart+C-1])&e.hash_mask;n=e.prev[e.strstart&e.w_mask]=e.head[e.ins_h];e.head[e.ins_h]=e.strstart}if(n!==0&&e.strstart-n<=e.w_size-E){e.match_length=ue(e,n)}if(e.match_length>=C){i=h._tr_tally(e,e.strstart-e.match_start,e.match_length-C);e.lookahead-=e.match_length;if(e.match_length<=e.max_lazy_match&&e.lookahead>=C){e.match_length--;do{e.strstart++;e.ins_h=(e.ins_h<<e.hash_shift^e.window[e.strstart+C-1])&e.hash_mask;n=e.prev[e.strstart&e.w_mask]=e.head[e.ins_h];e.head[e.ins_h]=e.strstart}while(--e.match_length!==0);e.strstart++}else{e.strstart+=e.match_length;e.match_length=0;e.ins_h=e.window[e.strstart];e.ins_h=(e.ins_h<<e.hash_shift^e.window[e.strstart+1])&e.hash_mask}}else{i=h._tr_tally(e,0,e.window[e.strstart]);e.lookahead--;e.strstart++}if(i){o(e,false);if(e.strm.avail_out===0){return S}}}e.insert=e.strstart<C-1?e.strstart:C-1;if(t===d){o(e,true);if(e.strm.avail_out===0){return O}return I}if(e.last_lit){o(e,false);if(e.strm.avail_out===0){return S}}return T}function i(e,t){var n;var i;var r;for(;;){if(e.lookahead<E){M(e);if(e.lookahead<E&&t===c){return S}if(e.lookahead===0){break}}n=0;if(e.lookahead>=C){e.ins_h=(e.ins_h<<e.hash_shift^e.window[e.strstart+C-1])&e.hash_mask;n=e.prev[e.strstart&e.w_mask]=e.head[e.ins_h];e.head[e.ins_h]=e.strstart}e.prev_length=e.match_length;e.prev_match=e.match_start;e.match_length=C-1;if(n!==0&&e.prev_length<e.max_lazy_match&&e.strstart-n<=e.w_size-E){e.match_length=ue(e,n);if(e.match_length<=5&&(e.strategy===H||e.match_length===C&&e.strstart-e.match_start>4096)){e.match_length=C-1}}if(e.prev_length>=C&&e.match_length<=e.prev_length){r=e.strstart+e.lookahead-C;i=h._tr_tally(e,e.strstart-1-e.prev_match,e.prev_length-C);e.lookahead-=e.prev_length-1;e.prev_length-=2;do{if(++e.strstart<=r){e.ins_h=(e.ins_h<<e.hash_shift^e.window[e.strstart+C-1])&e.hash_mask;n=e.prev[e.strstart&e.w_mask]=e.head[e.ins_h];e.head[e.ins_h]=e.strstart}}while(--e.prev_length!==0);e.match_available=0;e.match_length=C-1;e.strstart++;if(i){o(e,false);if(e.strm.avail_out===0){return S}}}else if(e.match_available){i=h._tr_tally(e,0,e.window[e.strstart-1]);if(i){o(e,false)}e.strstart++;e.lookahead--;if(e.strm.avail_out===0){return S}}else{e.match_available=1;e.strstart++;e.lookahead--}}if(e.match_available){i=h._tr_tally(e,0,e.window[e.strstart-1]);e.match_available=0}e.insert=e.strstart<C-1?e.strstart:C-1;if(t===d){o(e,true);if(e.strm.avail_out===0){return O}return I}if(e.last_lit){o(e,false);if(e.strm.avail_out===0){return S}}return T}function de(e,t){var n;var i;var r,s;var a=e.window;for(;;){if(e.lookahead<=_){M(e);if(e.lookahead<=_&&t===c){return S}if(e.lookahead===0){break}}e.match_length=0;if(e.lookahead>=C&&e.strstart>0){r=e.strstart-1;i=a[r];if(i===a[++r]&&i===a[++r]&&i===a[++r]){s=e.strstart+_;do{}while(i===a[++r]&&i===a[++r]&&i===a[++r]&&i===a[++r]&&i===a[++r]&&i===a[++r]&&i===a[++r]&&i===a[++r]&&r<s);e.match_length=_-(s-r);if(e.match_length>e.lookahead){e.match_length=e.lookahead}}}if(e.match_length>=C){n=h._tr_tally(e,1,e.match_length-C);e.lookahead-=e.match_length;e.strstart+=e.match_length;e.match_length=0}else{n=h._tr_tally(e,0,e.window[e.strstart]);e.lookahead--;e.strstart++}if(n){o(e,false);if(e.strm.avail_out===0){return S}}}e.insert=0;if(t===d){o(e,true);if(e.strm.avail_out===0){return O}return I}if(e.last_lit){o(e,false);if(e.strm.avail_out===0){return S}}return T}function me(e,t){var n;for(;;){if(e.lookahead===0){M(e);if(e.lookahead===0){if(t===c){return S}break}}e.match_length=0;n=h._tr_tally(e,0,e.window[e.strstart]);e.lookahead--;e.strstart++;if(n){o(e,false);if(e.strm.avail_out===0){return S}}}e.insert=0;if(t===d){o(e,true);if(e.strm.avail_out===0){return O}return I}if(e.last_lit){o(e,false);if(e.strm.avail_out===0){return S}}return T}function r(e,t,n,i,r){this.good_length=e;this.max_lazy=t;this.nice_length=n;this.max_chain=i;this.func=r}var P;P=[new r(0,0,0,0,fe),new r(4,4,8,4,ce),new r(4,5,16,8,ce),new r(4,6,32,32,ce),new r(4,4,16,16,i),new r(8,16,32,32,i),new r(8,16,128,128,i),new r(8,32,128,256,i),new r(32,128,258,1024,i),new r(32,258,258,4096,i)];function ge(e){e.window_size=2*e.w_size;L(e.head);e.max_lazy_match=P[e.level].max_lazy;e.good_match=P[e.level].good_length;e.nice_match=P[e.level].nice_length;e.max_chain_length=P[e.level].max_chain;e.strstart=0;e.block_start=0;e.lookahead=0;e.insert=0;e.match_length=e.prev_length=C-1;e.match_available=0;e.ins_h=0}function pe(){this.strm=null;this.status=0;this.pending_buf=null;this.pending_buf_size=0;this.pending_out=0;this.pending=0;this.wrap=0;this.gzhead=null;this.gzindex=0;this.method=A;this.last_flush=-1;this.w_size=0;this.w_bits=0;this.w_mask=0;this.window=null;this.window_size=0;this.prev=null;this.head=null;this.ins_h=0;this.hash_size=0;this.hash_bits=0;this.hash_mask=0;this.hash_shift=0;this.block_start=0;this.match_length=0;this.prev_match=0;this.match_available=0;this.strstart=0;this.match_start=0;this.lookahead=0;this.prev_length=0;this.max_chain_length=0;this.max_lazy_match=0;this.level=0;this.strategy=0;this.good_match=0;this.nice_match=0;this.dyn_ltree=new f.Buf16(ie*2);this.dyn_dtree=new f.Buf16((2*te+1)*2);this.bl_tree=new f.Buf16((2*ne+1)*2);L(this.dyn_ltree);L(this.dyn_dtree);L(this.bl_tree);this.l_desc=null;this.d_desc=null;this.bl_desc=null;this.bl_count=new f.Buf16(re+1);this.heap=new f.Buf16(2*n+1);L(this.heap);this.heap_len=0;this.heap_max=0;this.depth=new f.Buf16(2*n+1);L(this.depth);this.l_buf=0;this.lit_bufsize=0;this.last_lit=0;this.d_buf=0;this.opt_len=0;this.static_len=0;this.matches=0;this.insert=0;this.bi_buf=0;this.bi_valid=0}function Fe(e){var t;if(!e||!e.state){return w(e,g)}e.total_in=e.total_out=0;e.data_type=K;t=e.state;t.pending=0;t.pending_out=0;if(t.wrap<0){t.wrap=-t.wrap}t.status=t.wrap?v:y;e.adler=t.wrap===2?0:1;t.last_flush=c;h._tr_init(t);return m}function Ae(e){var t=Fe(e);if(t===m){ge(e.state)}return t}function Ce(e,t){if(!e||!e.state){return g}if(e.state.wrap!==2){return g}e.state.gzhead=t;return m}function _e(e,t,n,i,r,s){if(!e){return g}var a=1;if(t===X){t=6}if(i<0){a=0;i=-i}else if(i>15){a=2;i-=16}if(r<1||r>Q||n!==A||i<8||i>15||t<0||t>9||s<0||s>Y){return w(e,g)}if(i===8){i=9}var o=new pe;e.state=o;o.strm=e;o.wrap=a;o.gzhead=null;o.w_bits=i;o.w_size=1<<o.w_bits;o.w_mask=o.w_size-1;o.hash_bits=r+7;o.hash_size=1<<o.hash_bits;o.hash_mask=o.hash_size-1;o.hash_shift=~~((o.hash_bits+C-1)/C);o.window=new f.Buf8(o.w_size*2);o.head=new f.Buf16(o.hash_size);o.prev=new f.Buf16(o.w_size);o.lit_bufsize=1<<r+6;o.pending_buf_size=o.lit_bufsize*4;o.pending_buf=new f.Buf8(o.pending_buf_size);o.d_buf=1*o.lit_bufsize;o.l_buf=(1+2)*o.lit_bufsize;o.level=t;o.strategy=s;o.method=n;return Ae(e)}function Ee(e,t){return _e(e,t,A,q,J,Z)}function ve(e,t){var n,i;var r,s;if(!e||!e.state||t>j||t<0){return e?w(e,g):g}i=e.state;if(!e.output||!e.input&&e.avail_in!==0||i.status===x&&t!==d){return w(e,e.avail_out===0?p:g)}i.strm=e;n=i.last_flush;i.last_flush=t;if(i.status===v){if(i.wrap===2){e.adler=0;R(i,31);R(i,139);R(i,8);if(!i.gzhead){R(i,0);R(i,0);R(i,0);R(i,0);R(i,0);R(i,i.level===9?2:i.strategy>=F||i.level<2?4:0);R(i,oe);i.status=y}else{R(i,(i.gzhead.text?1:0)+(i.gzhead.hcrc?2:0)+(!i.gzhead.extra?0:4)+(!i.gzhead.name?0:8)+(!i.gzhead.comment?0:16));R(i,i.gzhead.time&255);R(i,i.gzhead.time>>8&255);R(i,i.gzhead.time>>16&255);R(i,i.gzhead.time>>24&255);R(i,i.level===9?2:i.strategy>=F||i.level<2?4:0);R(i,i.gzhead.os&255);if(i.gzhead.extra&&i.gzhead.extra.length){R(i,i.gzhead.extra.length&255);R(i,i.gzhead.extra.length>>8&255)}if(i.gzhead.hcrc){e.adler=u(e.adler,i.pending_buf,i.pending,0)}i.gzindex=0;i.status=ae}}else{var a=A+(i.w_bits-8<<4)<<8;var o=-1;if(i.strategy>=F||i.level<2){o=0}else if(i.level<6){o=1}else if(i.level===6){o=2}else{o=3}a|=o<<6;if(i.strstart!==0){a|=se}a+=31-a%31;i.status=y;k(i,a);if(i.strstart!==0){k(i,e.adler>>>16);k(i,e.adler&65535)}e.adler=1}}if(i.status===ae){if(i.gzhead.extra){r=i.pending;while(i.gzindex<(i.gzhead.extra.length&65535)){if(i.pending===i.pending_buf_size){if(i.gzhead.hcrc&&i.pending>r){e.adler=u(e.adler,i.pending_buf,i.pending-r,r)}N(e);r=i.pending;if(i.pending===i.pending_buf_size){break}}R(i,i.gzhead.extra[i.gzindex]&255);i.gzindex++}if(i.gzhead.hcrc&&i.pending>r){e.adler=u(e.adler,i.pending_buf,i.pending-r,r)}if(i.gzindex===i.gzhead.extra.length){i.gzindex=0;i.status=b}}else{i.status=b}}if(i.status===b){if(i.gzhead.name){r=i.pending;do{if(i.pending===i.pending_buf_size){if(i.gzhead.hcrc&&i.pending>r){e.adler=u(e.adler,i.pending_buf,i.pending-r,r)}N(e);r=i.pending;if(i.pending===i.pending_buf_size){s=1;break}}if(i.gzindex<i.gzhead.name.length){s=i.gzhead.name.charCodeAt(i.gzindex++)&255}else{s=0}R(i,s)}while(s!==0);if(i.gzhead.hcrc&&i.pending>r){e.adler=u(e.adler,i.pending_buf,i.pending-r,r)}if(s===0){i.gzindex=0;i.status=B}}else{i.status=B}}if(i.status===B){if(i.gzhead.comment){r=i.pending;do{if(i.pending===i.pending_buf_size){if(i.gzhead.hcrc&&i.pending>r){e.adler=u(e.adler,i.pending_buf,i.pending-r,r)}N(e);r=i.pending;if(i.pending===i.pending_buf_size){s=1;break}}if(i.gzindex<i.gzhead.comment.length){s=i.gzhead.comment.charCodeAt(i.gzindex++)&255}else{s=0}R(i,s)}while(s!==0);if(i.gzhead.hcrc&&i.pending>r){e.adler=u(e.adler,i.pending_buf,i.pending-r,r)}if(s===0){i.status=D}}else{i.status=D}}if(i.status===D){if(i.gzhead.hcrc){if(i.pending+2>i.pending_buf_size){N(e)}if(i.pending+2<=i.pending_buf_size){R(i,e.adler&255);R(i,e.adler>>8&255);e.adler=0;i.status=y}}else{i.status=y}}if(i.pending!==0){N(e);if(e.avail_out===0){i.last_flush=-1;return m}}else if(e.avail_in===0&&le(t)<=le(n)&&t!==d){return w(e,p)}if(i.status===x&&e.avail_in!==0){return w(e,p)}if(e.avail_in!==0||i.lookahead!==0||t!==c&&i.status!==x){var l=i.strategy===F?me(i,t):i.strategy===W?de(i,t):P[i.level].func(i,t);if(l===O||l===I){i.status=x}if(l===S||l===O){if(e.avail_out===0){i.last_flush=-1}return m}if(l===T){if(t===V){h._tr_align(i)}else if(t!==j){h._tr_stored_block(i,0,0,false);if(t===G){L(i.head);if(i.lookahead===0){i.strstart=0;i.block_start=0;i.insert=0}}}N(e);if(e.avail_out===0){i.last_flush=-1;return m}}}if(t!==d){return m}if(i.wrap<=0){return z}if(i.wrap===2){R(i,e.adler&255);R(i,e.adler>>8&255);R(i,e.adler>>16&255);R(i,e.adler>>24&255);R(i,e.total_in&255);R(i,e.total_in>>8&255);R(i,e.total_in>>16&255);R(i,e.total_in>>24&255)}else{k(i,e.adler>>>16);k(i,e.adler&65535)}N(e);if(i.wrap>0){i.wrap=-i.wrap}return i.pending!==0?m:z}function be(e){var t;if(!e||!e.state){return g}t=e.state.status;if(t!==v&&t!==ae&&t!==b&&t!==B&&t!==D&&t!==y&&t!==x){return w(e,g)}e.state=null;return t===y?w(e,l):m}function Be(e,t){var n=t.length;var i;var r,s;var a;var o;var l;var h;var u;if(!e||!e.state){return g}i=e.state;a=i.wrap;if(a===2||a===1&&i.status!==v||i.lookahead){return g}if(a===1){e.adler=U(e.adler,t,n,0)}i.wrap=0;if(n>=i.w_size){if(a===0){L(i.head);i.strstart=0;i.block_start=0;i.insert=0}u=new f.Buf8(i.w_size);f.arraySet(u,t,n-i.w_size,i.w_size,0);t=u;n=i.w_size}o=e.avail_in;l=e.next_in;h=e.input;e.avail_in=n;e.next_in=0;e.input=t;M(i);while(i.lookahead>=C){r=i.strstart;s=i.lookahead-(C-1);do{i.ins_h=(i.ins_h<<i.hash_shift^i.window[r+C-1])&i.hash_mask;i.prev[r&i.w_mask]=i.head[i.ins_h];i.head[i.ins_h]=r;r++}while(--s);i.strstart=r;i.lookahead=C-1;M(i)}i.strstart+=i.lookahead;i.block_start=i.strstart;i.insert=i.lookahead;i.lookahead=0;i.match_length=i.prev_length=C-1;i.match_available=0;e.next_in=l;e.input=h;e.avail_in=o;i.wrap=a;return m}t.deflateInit=Ee;t.deflateInit2=_e;t.deflateReset=Ae;t.deflateResetKeep=Fe;t.deflateSetHeader=Ce;t.deflate=ve;t.deflateEnd=be;t.deflateSetDictionary=Be;t.deflateInfo="pako deflate (from Nodeca project)"},{"../utils/common":41,"./adler32":43,"./crc32":45,"./messages":51,"./trees":52}],47:[function(e,t,n){"use strict";function i(){this.text=0;this.time=0;this.xflags=0;this.os=0;this.extra=null;this.extra_len=0;this.name="";this.comment="";this.hcrc=0;this.done=false}t.exports=i},{}],48:[function(e,t,n){"use strict";var S=30;var T=12;t.exports=function e(t,n){var i;var r;var s;var a;var o;var l;var h;var u;var f;var c;var d;var m;var g;var p;var F;var A;var C;var _;var E;var v;var b;var B;var D;var y,x;i=t.state;r=t.next_in;y=t.input;s=r+(t.avail_in-5);a=t.next_out;x=t.output;o=a-(n-t.avail_out);l=a+(t.avail_out-257);h=i.dmax;u=i.wsize;f=i.whave;c=i.wnext;d=i.window;m=i.hold;g=i.bits;p=i.lencode;F=i.distcode;A=(1<<i.lenbits)-1;C=(1<<i.distbits)-1;e:do{if(g<15){m+=y[r++]<<g;g+=8;m+=y[r++]<<g;g+=8}_=p[m&A];t:for(;;){E=_>>>24;m>>>=E;g-=E;E=_>>>16&255;if(E===0){x[a++]=_&65535}else if(E&16){v=_&65535;E&=15;if(E){if(g<E){m+=y[r++]<<g;g+=8}v+=m&(1<<E)-1;m>>>=E;g-=E}if(g<15){m+=y[r++]<<g;g+=8;m+=y[r++]<<g;g+=8}_=F[m&C];n:for(;;){E=_>>>24;m>>>=E;g-=E;E=_>>>16&255;if(E&16){b=_&65535;E&=15;if(g<E){m+=y[r++]<<g;g+=8;if(g<E){m+=y[r++]<<g;g+=8}}b+=m&(1<<E)-1;if(b>h){t.msg="invalid distance too far back";i.mode=S;break e}m>>>=E;g-=E;E=a-o;if(b>E){E=b-E;if(E>f){if(i.sane){t.msg="invalid distance too far back";i.mode=S;break e}}B=0;D=d;if(c===0){B+=u-E;if(E<v){v-=E;do{x[a++]=d[B++]}while(--E);B=a-b;D=x}}else if(c<E){B+=u+c-E;E-=c;if(E<v){v-=E;do{x[a++]=d[B++]}while(--E);B=0;if(c<v){E=c;v-=E;do{x[a++]=d[B++]}while(--E);B=a-b;D=x}}}else{B+=c-E;if(E<v){v-=E;do{x[a++]=d[B++]}while(--E);B=a-b;D=x}}while(v>2){x[a++]=D[B++];x[a++]=D[B++];x[a++]=D[B++];v-=3}if(v){x[a++]=D[B++];if(v>1){x[a++]=D[B++]}}}else{B=a-b;do{x[a++]=x[B++];x[a++]=x[B++];x[a++]=x[B++];v-=3}while(v>2);if(v){x[a++]=x[B++];if(v>1){x[a++]=x[B++]}}}}else if((E&64)===0){_=F[(_&65535)+(m&(1<<E)-1)];continue n}else{t.msg="invalid distance code";i.mode=S;break e}break}}else if((E&64)===0){_=p[(_&65535)+(m&(1<<E)-1)];continue t}else if(E&32){i.mode=T;break e}else{t.msg="invalid literal/length code";i.mode=S;break e}break}}while(r<s&&a<l);v=g>>3;r-=v;g-=v<<3;m&=(1<<g)-1;t.next_in=r;t.next_out=a;t.avail_in=r<s?5+(s-r):5-(r-s);t.avail_out=a<l?257+(l-a):257-(a-l);i.hold=m;i.bits=g;return}},{}],49:[function(e,r,t){"use strict";var T=e("../utils/common");var O=e("./adler32");var I=e("./crc32");var oe=e("./inffast");var w=e("./inftrees");var le=0;var L=1;var N=2;var R=4;var he=5;var k=6;var M=0;var ue=1;var fe=2;var P=-2;var U=-3;var V=-4;var ce=-5;var G=8;var j=1;var z=2;var X=3;var H=4;var W=5;var Y=6;var Z=7;var K=8;var Q=9;var q=10;var J=11;var $=12;var ee=13;var de=14;var te=15;var me=16;var ge=17;var pe=18;var Fe=19;var ne=20;var ie=21;var Ae=22;var Ce=23;var _e=24;var Ee=25;var ve=26;var re=27;var be=28;var Be=29;var se=30;var ae=31;var De=32;var s=852;var a=592;var o=15;var l=o;function ye(e){return(e>>>24&255)+(e>>>8&65280)+((e&65280)<<8)+((e&255)<<24)}function h(){this.mode=0;this.last=false;this.wrap=0;this.havedict=false;this.flags=0;this.dmax=0;this.check=0;this.total=0;this.head=null;this.wbits=0;this.wsize=0;this.whave=0;this.wnext=0;this.window=null;this.hold=0;this.bits=0;this.length=0;this.offset=0;this.extra=0;this.lencode=null;this.distcode=null;this.lenbits=0;this.distbits=0;this.ncode=0;this.nlen=0;this.ndist=0;this.have=0;this.next=null;this.lens=new T.Buf16(320);this.work=new T.Buf16(288);this.lendyn=null;this.distdyn=null;this.sane=0;this.back=0;this.was=0}function u(e){var t;if(!e||!e.state){return P}t=e.state;e.total_in=e.total_out=t.total=0;e.msg="";if(t.wrap){e.adler=t.wrap&1}t.mode=j;t.last=0;t.havedict=0;t.dmax=32768;t.head=null;t.hold=0;t.bits=0;t.lencode=t.lendyn=new T.Buf32(s);t.distcode=t.distdyn=new T.Buf32(a);t.sane=1;t.back=-1;return M}function f(e){var t;if(!e||!e.state){return P}t=e.state;t.wsize=0;t.whave=0;t.wnext=0;return u(e)}function c(e,t){var n;var i;if(!e||!e.state){return P}i=e.state;if(t<0){n=0;t=-t}else{n=(t>>4)+1;if(t<48){t&=15}}if(t&&(t<8||t>15)){return P}if(i.window!==null&&i.wbits!==t){i.window=null}i.wrap=n;i.wbits=t;return f(e)}function d(e,t){var n;var i;if(!e){return P}i=new h;e.state=i;i.window=null;n=c(e,t);if(n!==M){e.state=null}return n}function m(e){return d(e,l)}var g=true;var n,i;function xe(e){if(g){var t;n=new T.Buf32(512);i=new T.Buf32(32);t=0;while(t<144){e.lens[t++]=8}while(t<256){e.lens[t++]=9}while(t<280){e.lens[t++]=7}while(t<288){e.lens[t++]=8}w(L,e.lens,0,288,n,0,e.work,{bits:9});t=0;while(t<32){e.lens[t++]=5}w(N,e.lens,0,32,i,0,e.work,{bits:5});g=false}e.lencode=n;e.lenbits=9;e.distcode=i;e.distbits=5}function Se(e,t,n,i){var r;var s=e.state;if(s.window===null){s.wsize=1<<s.wbits;s.wnext=0;s.whave=0;s.window=new T.Buf8(s.wsize)}if(i>=s.wsize){T.arraySet(s.window,t,n-s.wsize,s.wsize,0);s.wnext=0;s.whave=s.wsize}else{r=s.wsize-s.wnext;if(r>i){r=i}T.arraySet(s.window,t,n-i,r,s.wnext);i-=r;if(i){T.arraySet(s.window,t,n-i,i,0);s.wnext=i;s.whave=s.wsize}else{s.wnext+=r;if(s.wnext===s.wsize){s.wnext=0}if(s.whave<s.wsize){s.whave+=r}}}return 0}function p(e,t){var n;var i,r;var s;var a;var o,l;var h;var u;var f,c;var d;var m;var g;var p=0;var F,A,C;var _,E,v;var b;var B;var D=new T.Buf8(4);var y;var x;var S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];if(!e||!e.state||!e.output||!e.input&&e.avail_in!==0){return P}n=e.state;if(n.mode===$){n.mode=ee}a=e.next_out;r=e.output;l=e.avail_out;s=e.next_in;i=e.input;o=e.avail_in;h=n.hold;u=n.bits;f=o;c=l;B=M;e:for(;;){switch(n.mode){case j:if(n.wrap===0){n.mode=ee;break}while(u<16){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}if(n.wrap&2&&h===35615){n.check=0;D[0]=h&255;D[1]=h>>>8&255;n.check=I(n.check,D,2,0);h=0;u=0;n.mode=z;break}n.flags=0;if(n.head){n.head.done=false}if(!(n.wrap&1)||(((h&255)<<8)+(h>>8))%31){e.msg="incorrect header check";n.mode=se;break}if((h&15)!==G){e.msg="unknown compression method";n.mode=se;break}h>>>=4;u-=4;b=(h&15)+8;if(n.wbits===0){n.wbits=b}else if(b>n.wbits){e.msg="invalid window size";n.mode=se;break}n.dmax=1<<b;e.adler=n.check=1;n.mode=h&512?q:$;h=0;u=0;break;case z:while(u<16){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}n.flags=h;if((n.flags&255)!==G){e.msg="unknown compression method";n.mode=se;break}if(n.flags&57344){e.msg="unknown header flags set";n.mode=se;break}if(n.head){n.head.text=h>>8&1}if(n.flags&512){D[0]=h&255;D[1]=h>>>8&255;n.check=I(n.check,D,2,0)}h=0;u=0;n.mode=X;case X:while(u<32){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}if(n.head){n.head.time=h}if(n.flags&512){D[0]=h&255;D[1]=h>>>8&255;D[2]=h>>>16&255;D[3]=h>>>24&255;n.check=I(n.check,D,4,0)}h=0;u=0;n.mode=H;case H:while(u<16){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}if(n.head){n.head.xflags=h&255;n.head.os=h>>8}if(n.flags&512){D[0]=h&255;D[1]=h>>>8&255;n.check=I(n.check,D,2,0)}h=0;u=0;n.mode=W;case W:if(n.flags&1024){while(u<16){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}n.length=h;if(n.head){n.head.extra_len=h}if(n.flags&512){D[0]=h&255;D[1]=h>>>8&255;n.check=I(n.check,D,2,0)}h=0;u=0}else if(n.head){n.head.extra=null}n.mode=Y;case Y:if(n.flags&1024){d=n.length;if(d>o){d=o}if(d){if(n.head){b=n.head.extra_len-n.length;if(!n.head.extra){n.head.extra=new Array(n.head.extra_len)}T.arraySet(n.head.extra,i,s,d,b)}if(n.flags&512){n.check=I(n.check,i,d,s)}o-=d;s+=d;n.length-=d}if(n.length){break e}}n.length=0;n.mode=Z;case Z:if(n.flags&2048){if(o===0){break e}d=0;do{b=i[s+d++];if(n.head&&b&&n.length<65536){n.head.name+=String.fromCharCode(b)}}while(b&&d<o);if(n.flags&512){n.check=I(n.check,i,d,s)}o-=d;s+=d;if(b){break e}}else if(n.head){n.head.name=null}n.length=0;n.mode=K;case K:if(n.flags&4096){if(o===0){break e}d=0;do{b=i[s+d++];if(n.head&&b&&n.length<65536){n.head.comment+=String.fromCharCode(b)}}while(b&&d<o);if(n.flags&512){n.check=I(n.check,i,d,s)}o-=d;s+=d;if(b){break e}}else if(n.head){n.head.comment=null}n.mode=Q;case Q:if(n.flags&512){while(u<16){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}if(h!==(n.check&65535)){e.msg="header crc mismatch";n.mode=se;break}h=0;u=0}if(n.head){n.head.hcrc=n.flags>>9&1;n.head.done=true}e.adler=n.check=0;n.mode=$;break;case q:while(u<32){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}e.adler=n.check=ye(h);h=0;u=0;n.mode=J;case J:if(n.havedict===0){e.next_out=a;e.avail_out=l;e.next_in=s;e.avail_in=o;n.hold=h;n.bits=u;return fe}e.adler=n.check=1;n.mode=$;case $:if(t===he||t===k){break e}case ee:if(n.last){h>>>=u&7;u-=u&7;n.mode=re;break}while(u<3){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}n.last=h&1;h>>>=1;u-=1;switch(h&3){case 0:n.mode=de;break;case 1:xe(n);n.mode=ne;if(t===k){h>>>=2;u-=2;break e}break;case 2:n.mode=ge;break;case 3:e.msg="invalid block type";n.mode=se}h>>>=2;u-=2;break;case de:h>>>=u&7;u-=u&7;while(u<32){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}if((h&65535)!==(h>>>16^65535)){e.msg="invalid stored block lengths";n.mode=se;break}n.length=h&65535;h=0;u=0;n.mode=te;if(t===k){break e}case te:n.mode=me;case me:d=n.length;if(d){if(d>o){d=o}if(d>l){d=l}if(d===0){break e}T.arraySet(r,i,s,d,a);o-=d;s+=d;l-=d;a+=d;n.length-=d;break}n.mode=$;break;case ge:while(u<14){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}n.nlen=(h&31)+257;h>>>=5;u-=5;n.ndist=(h&31)+1;h>>>=5;u-=5;n.ncode=(h&15)+4;h>>>=4;u-=4;if(n.nlen>286||n.ndist>30){e.msg="too many length or distance symbols";n.mode=se;break}n.have=0;n.mode=pe;case pe:while(n.have<n.ncode){while(u<3){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}n.lens[S[n.have++]]=h&7;h>>>=3;u-=3}while(n.have<19){n.lens[S[n.have++]]=0}n.lencode=n.lendyn;n.lenbits=7;y={bits:n.lenbits};B=w(le,n.lens,0,19,n.lencode,0,n.work,y);n.lenbits=y.bits;if(B){e.msg="invalid code lengths set";n.mode=se;break}n.have=0;n.mode=Fe;case Fe:while(n.have<n.nlen+n.ndist){for(;;){p=n.lencode[h&(1<<n.lenbits)-1];F=p>>>24;A=p>>>16&255;C=p&65535;if(F<=u){break}if(o===0){break e}o--;h+=i[s++]<<u;u+=8}if(C<16){h>>>=F;u-=F;n.lens[n.have++]=C}else{if(C===16){x=F+2;while(u<x){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}h>>>=F;u-=F;if(n.have===0){e.msg="invalid bit length repeat";n.mode=se;break}b=n.lens[n.have-1];d=3+(h&3);h>>>=2;u-=2}else if(C===17){x=F+3;while(u<x){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}h>>>=F;u-=F;b=0;d=3+(h&7);h>>>=3;u-=3}else{x=F+7;while(u<x){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}h>>>=F;u-=F;b=0;d=11+(h&127);h>>>=7;u-=7}if(n.have+d>n.nlen+n.ndist){e.msg="invalid bit length repeat";n.mode=se;break}while(d--){n.lens[n.have++]=b}}}if(n.mode===se){break}if(n.lens[256]===0){e.msg="invalid code -- missing end-of-block";n.mode=se;break}n.lenbits=9;y={bits:n.lenbits};B=w(L,n.lens,0,n.nlen,n.lencode,0,n.work,y);n.lenbits=y.bits;if(B){e.msg="invalid literal/lengths set";n.mode=se;break}n.distbits=6;n.distcode=n.distdyn;y={bits:n.distbits};B=w(N,n.lens,n.nlen,n.ndist,n.distcode,0,n.work,y);n.distbits=y.bits;if(B){e.msg="invalid distances set";n.mode=se;break}n.mode=ne;if(t===k){break e}case ne:n.mode=ie;case ie:if(o>=6&&l>=258){e.next_out=a;e.avail_out=l;e.next_in=s;e.avail_in=o;n.hold=h;n.bits=u;oe(e,c);a=e.next_out;r=e.output;l=e.avail_out;s=e.next_in;i=e.input;o=e.avail_in;h=n.hold;u=n.bits;if(n.mode===$){n.back=-1}break}n.back=0;for(;;){p=n.lencode[h&(1<<n.lenbits)-1];F=p>>>24;A=p>>>16&255;C=p&65535;if(F<=u){break}if(o===0){break e}o--;h+=i[s++]<<u;u+=8}if(A&&(A&240)===0){_=F;E=A;v=C;for(;;){p=n.lencode[v+((h&(1<<_+E)-1)>>_)];F=p>>>24;A=p>>>16&255;C=p&65535;if(_+F<=u){break}if(o===0){break e}o--;h+=i[s++]<<u;u+=8}h>>>=_;u-=_;n.back+=_}h>>>=F;u-=F;n.back+=F;n.length=C;if(A===0){n.mode=ve;break}if(A&32){n.back=-1;n.mode=$;break}if(A&64){e.msg="invalid literal/length code";n.mode=se;break}n.extra=A&15;n.mode=Ae;case Ae:if(n.extra){x=n.extra;while(u<x){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}n.length+=h&(1<<n.extra)-1;h>>>=n.extra;u-=n.extra;n.back+=n.extra}n.was=n.length;n.mode=Ce;case Ce:for(;;){p=n.distcode[h&(1<<n.distbits)-1];F=p>>>24;A=p>>>16&255;C=p&65535;if(F<=u){break}if(o===0){break e}o--;h+=i[s++]<<u;u+=8}if((A&240)===0){_=F;E=A;v=C;for(;;){p=n.distcode[v+((h&(1<<_+E)-1)>>_)];F=p>>>24;A=p>>>16&255;C=p&65535;if(_+F<=u){break}if(o===0){break e}o--;h+=i[s++]<<u;u+=8}h>>>=_;u-=_;n.back+=_}h>>>=F;u-=F;n.back+=F;if(A&64){e.msg="invalid distance code";n.mode=se;break}n.offset=C;n.extra=A&15;n.mode=_e;case _e:if(n.extra){x=n.extra;while(u<x){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}n.offset+=h&(1<<n.extra)-1;h>>>=n.extra;u-=n.extra;n.back+=n.extra}if(n.offset>n.dmax){e.msg="invalid distance too far back";n.mode=se;break}n.mode=Ee;case Ee:if(l===0){break e}d=c-l;if(n.offset>d){d=n.offset-d;if(d>n.whave){if(n.sane){e.msg="invalid distance too far back";n.mode=se;break}}if(d>n.wnext){d-=n.wnext;m=n.wsize-d}else{m=n.wnext-d}if(d>n.length){d=n.length}g=n.window}else{g=r;m=a-n.offset;d=n.length}if(d>l){d=l}l-=d;n.length-=d;do{r[a++]=g[m++]}while(--d);if(n.length===0){n.mode=ie}break;case ve:if(l===0){break e}r[a++]=n.length;l--;n.mode=ie;break;case re:if(n.wrap){while(u<32){if(o===0){break e}o--;h|=i[s++]<<u;u+=8}c-=l;e.total_out+=c;n.total+=c;if(c){e.adler=n.check=n.flags?I(n.check,r,c,a-c):O(n.check,r,c,a-c)}c=l;if((n.flags?h:ye(h))!==n.check){e.msg="incorrect data check";n.mode=se;break}h=0;u=0}n.mode=be;case be:if(n.wrap&&n.flags){while(u<32){if(o===0){break e}o--;h+=i[s++]<<u;u+=8}if(h!==(n.total&4294967295)){e.msg="incorrect length check";n.mode=se;break}h=0;u=0}n.mode=Be;case Be:B=ue;break e;case se:B=U;break e;case ae:return V;case De:default:return P}}e.next_out=a;e.avail_out=l;e.next_in=s;e.avail_in=o;n.hold=h;n.bits=u;if(n.wsize||c!==e.avail_out&&n.mode<se&&(n.mode<re||t!==R)){if(Se(e,e.output,e.next_out,c-e.avail_out)){n.mode=ae;return V}}f-=e.avail_in;c-=e.avail_out;e.total_in+=f;e.total_out+=c;n.total+=c;if(n.wrap&&c){e.adler=n.check=n.flags?I(n.check,r,c,e.next_out-c):O(n.check,r,c,e.next_out-c)}e.data_type=n.bits+(n.last?64:0)+(n.mode===$?128:0)+(n.mode===ne||n.mode===te?256:0);if((f===0&&c===0||t===R)&&B===M){B=ce}return B}function F(e){if(!e||!e.state){return P}var t=e.state;if(t.window){t.window=null}e.state=null;return M}function A(e,t){var n;if(!e||!e.state){return P}n=e.state;if((n.wrap&2)===0){return P}n.head=t;t.done=false;return M}function C(e,t){var n=t.length;var i;var r;var s;if(!e||!e.state){return P}i=e.state;if(i.wrap!==0&&i.mode!==J){return P}if(i.mode===J){r=1;r=O(r,t,n,0);if(r!==i.check){return U}}s=Se(e,t,n,n);if(s){i.mode=ae;return V}i.havedict=1;return M}t.inflateReset=f;t.inflateReset2=c;t.inflateResetKeep=u;t.inflateInit=m;t.inflateInit2=d;t.inflate=p;t.inflateEnd=F;t.inflateGetHeader=A;t.inflateSetDictionary=C;t.inflateInfo="pako inflate (from Nodeca project)"},{"../utils/common":41,"./adler32":43,"./crc32":45,"./inffast":48,"./inftrees":50}],50:[function(e,t,n){"use strict";var R=e("../utils/common");var k=15;var M=852;var P=592;var U=0;var V=1;var G=2;var j=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0];var z=[16,16,16,16,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,16,72,78];var X=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0];var H=[16,16,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,64,64];t.exports=function e(t,n,i,r,s,a,o,l){var h=l.bits;var u=0;var f=0;var c=0,d=0;var m=0;var g=0;var p=0;var F=0;var A=0;var C=0;var _;var E;var v;var b;var B;var D=null;var y=0;var x;var S=new R.Buf16(k+1);var T=new R.Buf16(k+1);var O=null;var I=0;var w,L,N;for(u=0;u<=k;u++){S[u]=0}for(f=0;f<r;f++){S[n[i+f]]++}m=h;for(d=k;d>=1;d--){if(S[d]!==0){break}}if(m>d){m=d}if(d===0){s[a++]=1<<24|64<<16|0;s[a++]=1<<24|64<<16|0;l.bits=1;return 0}for(c=1;c<d;c++){if(S[c]!==0){break}}if(m<c){m=c}F=1;for(u=1;u<=k;u++){F<<=1;F-=S[u];if(F<0){return-1}}if(F>0&&(t===U||d!==1)){return-1}T[1]=0;for(u=1;u<k;u++){T[u+1]=T[u]+S[u]}for(f=0;f<r;f++){if(n[i+f]!==0){o[T[n[i+f]]++]=f}}if(t===U){D=O=o;x=19}else if(t===V){D=j;y-=257;O=z;I-=257;x=256}else{D=X;O=H;x=-1}C=0;f=0;u=c;B=a;g=m;p=0;v=-1;A=1<<m;b=A-1;if(t===V&&A>M||t===G&&A>P){return 1}for(;;){w=u-p;if(o[f]<x){L=0;N=o[f]}else if(o[f]>x){L=O[I+o[f]];N=D[y+o[f]]}else{L=32+64;N=0}_=1<<u-p;E=1<<g;c=E;do{E-=_;s[B+(C>>p)+E]=w<<24|L<<16|N|0}while(E!==0);_=1<<u-1;while(C&_){_>>=1}if(_!==0){C&=_-1;C+=_}else{C=0}f++;if(--S[u]===0){if(u===d){break}u=n[i+o[f]]}if(u>m&&(C&b)!==v){if(p===0){p=m}B+=c;g=u-p;F=1<<g;while(g+p<d){F-=S[g+p];if(F<=0){break}g++;F<<=1}A+=1<<g;if(t===V&&A>M||t===G&&A>P){return 1}v=C&b;s[v]=m<<24|g<<16|B-a|0}}if(C!==0){s[B+C]=u-p<<24|64<<16|0}l.bits=m;return 0}},{"../utils/common":41}],51:[function(e,t,n){"use strict";t.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],52:[function(k,M,e){"use strict";var P=k("../utils/common");var U=4;var i=0;var r=1;var V=2;function t(e){var t=e.length;while(--t>=0){e[t]=0}}var G=0;var o=1;var j=2;var z=3;var X=258;var a=29;var l=256;var h=l+1+a;var u=30;var f=19;var p=2*h+1;var F=15;var s=16;var H=7;var c=256;var d=16;var m=17;var g=18;var A=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];var C=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];var W=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];var _=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];var Y=512;var E=new Array((h+2)*2);t(E);var v=new Array(u*2);t(v);var b=new Array(Y);t(b);var B=new Array(X-z+1);t(B);var D=new Array(a);t(D);var y=new Array(u);t(y);function x(e,t,n,i,r){this.static_tree=e;this.extra_bits=t;this.extra_base=n;this.elems=i;this.max_length=r;this.has_stree=e&&e.length}var S;var T;var O;function n(e,t){this.dyn_tree=e;this.max_code=0;this.stat_desc=t}function Z(e){return e<256?b[e]:b[256+(e>>>7)]}function I(e,t){e.pending_buf[e.pending++]=t&255;e.pending_buf[e.pending++]=t>>>8&255}function w(e,t,n){if(e.bi_valid>s-n){e.bi_buf|=t<<e.bi_valid&65535;I(e,e.bi_buf);e.bi_buf=t>>s-e.bi_valid;e.bi_valid+=n-s}else{e.bi_buf|=t<<e.bi_valid&65535;e.bi_valid+=n}}function L(e,t,n){w(e,n[t*2],n[t*2+1])}function K(e,t){var n=0;do{n|=e&1;e>>>=1;n<<=1}while(--t>0);return n>>>1}function Q(e){if(e.bi_valid===16){I(e,e.bi_buf);e.bi_buf=0;e.bi_valid=0}else if(e.bi_valid>=8){e.pending_buf[e.pending++]=e.bi_buf&255;e.bi_buf>>=8;e.bi_valid-=8}}function q(e,t){var n=t.dyn_tree;var i=t.max_code;var r=t.stat_desc.static_tree;var s=t.stat_desc.has_stree;var a=t.stat_desc.extra_bits;var o=t.stat_desc.extra_base;var l=t.stat_desc.max_length;var h;var u,f;var c;var d;var m;var g=0;for(c=0;c<=F;c++){e.bl_count[c]=0}n[e.heap[e.heap_max]*2+1]=0;for(h=e.heap_max+1;h<p;h++){u=e.heap[h];c=n[n[u*2+1]*2+1]+1;if(c>l){c=l;g++}n[u*2+1]=c;if(u>i){continue}e.bl_count[c]++;d=0;if(u>=o){d=a[u-o]}m=n[u*2];e.opt_len+=m*(c+d);if(s){e.static_len+=m*(r[u*2+1]+d)}}if(g===0){return}do{c=l-1;while(e.bl_count[c]===0){c--}e.bl_count[c]--;e.bl_count[c+1]+=2;e.bl_count[l]--;g-=2}while(g>0);for(c=l;c!==0;c--){u=e.bl_count[c];while(u!==0){f=e.heap[--h];if(f>i){continue}if(n[f*2+1]!==c){e.opt_len+=(c-n[f*2+1])*n[f*2];n[f*2+1]=c}u--}}}function J(e,t,n){var i=new Array(F+1);var r=0;var s;var a;for(s=1;s<=F;s++){i[s]=r=r+n[s-1]<<1}for(a=0;a<=t;a++){var o=e[a*2+1];if(o===0){continue}e[a*2]=K(i[o]++,o)}}function $(){var e;var t;var n;var i;var r;var s=new Array(F+1);n=0;for(i=0;i<a-1;i++){D[i]=n;for(e=0;e<1<<A[i];e++){B[n++]=i}}B[n-1]=i;r=0;for(i=0;i<16;i++){y[i]=r;for(e=0;e<1<<C[i];e++){b[r++]=i}}r>>=7;for(;i<u;i++){y[i]=r<<7;for(e=0;e<1<<C[i]-7;e++){b[256+r++]=i}}for(t=0;t<=F;t++){s[t]=0}e=0;while(e<=143){E[e*2+1]=8;e++;s[8]++}while(e<=255){E[e*2+1]=9;e++;s[9]++}while(e<=279){E[e*2+1]=7;e++;s[7]++}while(e<=287){E[e*2+1]=8;e++;s[8]++}J(E,h+1,s);for(e=0;e<u;e++){v[e*2+1]=5;v[e*2]=K(e,5)}S=new x(E,A,l+1,h,F);T=new x(v,C,0,u,F);O=new x(new Array(0),W,0,f,H)}function ee(e){var t;for(t=0;t<h;t++){e.dyn_ltree[t*2]=0}for(t=0;t<u;t++){e.dyn_dtree[t*2]=0}for(t=0;t<f;t++){e.bl_tree[t*2]=0}e.dyn_ltree[c*2]=1;e.opt_len=e.static_len=0;e.last_lit=e.matches=0}function te(e){if(e.bi_valid>8){I(e,e.bi_buf)}else if(e.bi_valid>0){e.pending_buf[e.pending++]=e.bi_buf}e.bi_buf=0;e.bi_valid=0}function ne(e,t,n,i){te(e);if(i){I(e,n);I(e,~n)}P.arraySet(e.pending_buf,e.window,t,n,e.pending);e.pending+=n}function ie(e,t,n,i){var r=t*2;var s=n*2;return e[r]<e[s]||e[r]===e[s]&&i[t]<=i[n]}function N(e,t,n){var i=e.heap[n];var r=n<<1;while(r<=e.heap_len){if(r<e.heap_len&&ie(t,e.heap[r+1],e.heap[r],e.depth)){r++}if(ie(t,i,e.heap[r],e.depth)){break}e.heap[n]=e.heap[r];n=r;r<<=1}e.heap[n]=i}function re(e,t,n){var i;var r;var s=0;var a;var o;if(e.last_lit!==0){do{i=e.pending_buf[e.d_buf+s*2]<<8|e.pending_buf[e.d_buf+s*2+1];r=e.pending_buf[e.l_buf+s];s++;if(i===0){L(e,r,t)}else{a=B[r];L(e,a+l+1,t);o=A[a];if(o!==0){r-=D[a];w(e,r,o)}i--;a=Z(i);L(e,a,n);o=C[a];if(o!==0){i-=y[a];w(e,i,o)}}}while(s<e.last_lit)}L(e,c,t)}function R(e,t){var n=t.dyn_tree;var i=t.stat_desc.static_tree;var r=t.stat_desc.has_stree;var s=t.stat_desc.elems;var a,o;var l=-1;var h;e.heap_len=0;e.heap_max=p;for(a=0;a<s;a++){if(n[a*2]!==0){e.heap[++e.heap_len]=l=a;e.depth[a]=0}else{n[a*2+1]=0}}while(e.heap_len<2){h=e.heap[++e.heap_len]=l<2?++l:0;n[h*2]=1;e.depth[h]=0;e.opt_len--;if(r){e.static_len-=i[h*2+1]}}t.max_code=l;for(a=e.heap_len>>1;a>=1;a--){N(e,n,a)}h=s;do{a=e.heap[1];e.heap[1]=e.heap[e.heap_len--];N(e,n,1);o=e.heap[1];e.heap[--e.heap_max]=a;e.heap[--e.heap_max]=o;n[h*2]=n[a*2]+n[o*2];e.depth[h]=(e.depth[a]>=e.depth[o]?e.depth[a]:e.depth[o])+1;n[a*2+1]=n[o*2+1]=h;e.heap[1]=h++;N(e,n,1)}while(e.heap_len>=2);e.heap[--e.heap_max]=e.heap[1];q(e,t);J(n,l,e.bl_count)}function se(e,t,n){var i;var r=-1;var s;var a=t[0*2+1];var o=0;var l=7;var h=4;if(a===0){l=138;h=3}t[(n+1)*2+1]=65535;for(i=0;i<=n;i++){s=a;a=t[(i+1)*2+1];if(++o<l&&s===a){continue}else if(o<h){e.bl_tree[s*2]+=o}else if(s!==0){if(s!==r){e.bl_tree[s*2]++}e.bl_tree[d*2]++}else if(o<=10){e.bl_tree[m*2]++}else{e.bl_tree[g*2]++}o=0;r=s;if(a===0){l=138;h=3}else if(s===a){l=6;h=3}else{l=7;h=4}}}function ae(e,t,n){var i;var r=-1;var s;var a=t[0*2+1];var o=0;var l=7;var h=4;if(a===0){l=138;h=3}for(i=0;i<=n;i++){s=a;a=t[(i+1)*2+1];if(++o<l&&s===a){continue}else if(o<h){do{L(e,s,e.bl_tree)}while(--o!==0)}else if(s!==0){if(s!==r){L(e,s,e.bl_tree);o--}L(e,d,e.bl_tree);w(e,o-3,2)}else if(o<=10){L(e,m,e.bl_tree);w(e,o-3,3)}else{L(e,g,e.bl_tree);w(e,o-11,7)}o=0;r=s;if(a===0){l=138;h=3}else if(s===a){l=6;h=3}else{l=7;h=4}}}function oe(e){var t;se(e,e.dyn_ltree,e.l_desc.max_code);se(e,e.dyn_dtree,e.d_desc.max_code);R(e,e.bl_desc);for(t=f-1;t>=3;t--){if(e.bl_tree[_[t]*2+1]!==0){break}}e.opt_len+=3*(t+1)+5+5+4;return t}function le(e,t,n,i){var r;w(e,t-257,5);w(e,n-1,5);w(e,i-4,4);for(r=0;r<i;r++){w(e,e.bl_tree[_[r]*2+1],3)}ae(e,e.dyn_ltree,t-1);ae(e,e.dyn_dtree,n-1)}function he(e){var t=4093624447;var n;for(n=0;n<=31;n++,t>>>=1){if(t&1&&e.dyn_ltree[n*2]!==0){return i}}if(e.dyn_ltree[9*2]!==0||e.dyn_ltree[10*2]!==0||e.dyn_ltree[13*2]!==0){return r}for(n=32;n<l;n++){if(e.dyn_ltree[n*2]!==0){return r}}return i}var ue=false;function fe(e){if(!ue){$();ue=true}e.l_desc=new n(e.dyn_ltree,S);e.d_desc=new n(e.dyn_dtree,T);e.bl_desc=new n(e.bl_tree,O);e.bi_buf=0;e.bi_valid=0;ee(e)}function ce(e,t,n,i){w(e,(G<<1)+(i?1:0),3);ne(e,t,n,true)}function de(e){w(e,o<<1,3);L(e,c,E);Q(e)}function me(e,t,n,i){var r,s;var a=0;if(e.level>0){if(e.strm.data_type===V){e.strm.data_type=he(e)}R(e,e.l_desc);R(e,e.d_desc);a=oe(e);r=e.opt_len+3+7>>>3;s=e.static_len+3+7>>>3;if(s<=r){r=s}}else{r=s=n+5}if(n+4<=r&&t!==-1){ce(e,t,n,i)}else if(e.strategy===U||s===r){w(e,(o<<1)+(i?1:0),3);re(e,E,v)}else{w(e,(j<<1)+(i?1:0),3);le(e,e.l_desc.max_code+1,e.d_desc.max_code+1,a+1);re(e,e.dyn_ltree,e.dyn_dtree)}ee(e);if(i){te(e)}}function ge(e,t,n){e.pending_buf[e.d_buf+e.last_lit*2]=t>>>8&255;e.pending_buf[e.d_buf+e.last_lit*2+1]=t&255;e.pending_buf[e.l_buf+e.last_lit]=n&255;e.last_lit++;if(t===0){e.dyn_ltree[n*2]++}else{e.matches++;t--;e.dyn_ltree[(B[n]+l+1)*2]++;e.dyn_dtree[Z(t)*2]++}return e.last_lit===e.lit_bufsize-1}e._tr_init=fe;e._tr_stored_block=ce;e._tr_flush_block=me;e._tr_tally=ge;e._tr_align=de},{"../utils/common":41}],53:[function(e,t,n){"use strict";function i(){this.input=null;this.next_in=0;this.avail_in=0;this.total_in=0;this.output=null;this.next_out=0;this.avail_out=0;this.total_out=0;this.msg="";this.state=null;this.data_type=2;this.adler=0}t.exports=i},{}],54:[function(e,t,n){"use strict";t.exports=typeof setImmediate==="function"?setImmediate:function e(){var t=[].slice.apply(arguments);t.splice(1,0,0);setTimeout.apply(null,t)}},{}]},{},[10])(10)});(()=>{"use strict";var e={};class u{constructor(e,t){this.initiator=e;this._options=t}stack(e){console.info("["+this.initiator+"] ",e);console.log((new Error).stack)}groupCollapsed(e){if(CABLES.UI&&CABLES.UI.logFilter.filterLog({initiator:this.initiator,level:0},...arguments)||!CABLES.logSilent)console.log("["+this.initiator+"]",...arguments);console.groupCollapsed("["+this.initiator+"] "+e)}table(e){console.table(e)}groupEnd(){console.groupEnd()}error(){if(CABLES.UI&&CABLES.UI.logFilter.filterLog({initiator:this.initiator,level:2},...arguments)||!CABLES.UI){console.error("["+this.initiator+"]",...arguments)}if(this._options&&this._options.onError){this._options.onError(this.initiator,...arguments)}}errorGui(){if(CABLES.UI)CABLES.UI.logFilter.filterLog({initiator:this.initiator,level:2},...arguments)}warn(){if(CABLES.UI&&CABLES.UI.logFilter.filterLog({initiator:this.initiator,level:1},...arguments)||!CABLES.logSilent)console.warn("["+this.initiator+"]",...arguments)}verbose(){if(CABLES.UI&&CABLES.UI.logFilter.filterLog({initiator:this.initiator,level:0},...arguments)||!CABLES.logSilent)console.log("["+this.initiator+"]",...arguments)}info(){if(CABLES.UI&&CABLES.UI.logFilter.filterLog({initiator:this.initiator,level:0},...arguments)||!CABLES.logSilent)console.info("["+this.initiator+"]",...arguments)}log(){if(CABLES.UI&&CABLES.UI.logFilter.filterLog({initiator:this.initiator,level:0},...arguments)||!CABLES.logSilent)console.log("["+this.initiator+"]",...arguments)}logGui(){if(CABLES.UI)CABLES.UI.logFilter.filterLog({initiator:this.initiator,level:0},...arguments)}userInteraction(e){}}const r={};r.float32Concat=function(e,t){if(!(e instanceof Float32Array))e=new Float32Array(e);if(!(t instanceof Float32Array))t=new Float32Array(t);const n=new Float32Array(e.length+t.length);n.set(e);n.set(t,e.length);return n};const k=function(e){let t=e.split(".")[e.split(".").length-1];if(t.contains(CONSTANTS.OP.OP_VERSION_PREFIX)){const n=t.split(CONSTANTS.OP.OP_VERSION_PREFIX)[1];t=t.substring(0,t.length-(CONSTANTS.OP.OP_VERSION_PREFIX+n).length)}return t};const M=function(t){for(let e=t.length-1;e>0;e--){const n=Math.floor(Math.seededRandom()*(e+1));const i=t[e];t[e]=t[n];t[n]=i}return t};const t={};const n=function(){let e=Math.random().toString(36).substr(2,9);if(t.hasOwnProperty(e))e=n();t[e]=true;return e};const P=null&&n;const i=function(){let n=(new Date).getTime();const e="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=(n+Math.random()*16)%16|0;n=Math.floor(n/16);return(e=="x"?t:t&3|8).toString(16)});return e};const U=null&&i;const V=null&&i;function s(e){for(const t in e){if(e[t]&&typeof objValue==="object"&&e[t].constructor===Object)e[t]=s(e[t]);if(e[t]===null||e[t]===undefined)delete e[t];else if(Array.isArray(e[t])&&e[t].length==0)delete e[t]}return e}const a=function(n,e="id"){let i=0;if(Array.prototype.reduce){i=n.split("").reduce((e,t)=>{e=(e<<5)-e+t.charCodeAt(0);return e&e},0)}else{if(n.length>0){for(let t=0;t<n.length;t++){let e=n.charCodeAt(t);i=(i<<5)-i+e;i&=i}}}return e+""+i};const G=null&&a;let o=0;const j=function(){o++;return o};const z=function(e){const t=Math.max(0,Math.min(1,(e-0)/(1-0)));e=t*t*(3-2*t);return e};const X=function(e){const t=Math.max(0,Math.min(1,(e-0)/(1-0)));e=t*t*t*(t*(t*6-15)+10);return e};const H=function(e,t,n){return Math.min(Math.max(e,t),n)};const W=function(e,t,n,i,r,s){if(e>=n)return r;if(e<=t)return i;let a=false;const o=Math.min(t,n);const l=Math.max(t,n);if(o!=t)a=true;let h=false;const u=Math.min(i,r);const f=Math.max(i,r);if(u!=i)h=true;let c=0;let d=0;if(a)c=(l-e)*(f-u)/(l-o);else c=(e-o)*(f-u)/(l-o);if(h)d=f-c;else d=c+u;if(!s)return d;if(s==1){e=Math.max(0,Math.min(1,(d-i)/(r-i)));return i+e*e*(3-2*e)*(r-i)}if(s==2){e=Math.max(0,Math.min(1,(d-i)/(r-i)));return i+e*e*e*(e*(e*6-15)+10)*(r-i)}return d};Math.randomSeed=1;Math.setRandomSeed=function(e){Math.randomSeed=e*50728129;if(e!=0){Math.randomSeed=Math.seededRandom()*17624813;Math.randomSeed=Math.seededRandom()*9737333}};Math.seededRandom=function(e,t){if(Math.randomSeed===0)Math.randomSeed=Math.random()*999;e=e||1;t=t||0;Math.randomSeed=(Math.randomSeed*9301+49297)%233280;const n=Math.randomSeed/233280;return t+n*(e-t)};r.isNumeric=function(e){return!isNaN(parseFloat(e))&&isFinite(e)};r.isArray=function(e){return Object.prototype.toString.call(e)==="[object Array]"};String.prototype.endl=function(){return this+"\n"};String.prototype.startsWith=function(e){if(!this||!e)return false;if(this.length>=e.length){if(this.substring(0,e.length)==e)return true}return false};String.prototype.endsWith=String.prototype.endsWith||function(e){return this.match(e+"$")==e};String.prototype.contains=String.prototype.contains||function(e){return this.indexOf(e)>-1};const Y=function(e=""){if(!e)return"";if(e.startsWith("data:"))return;if(e.contains("?"))e+="&";else e+="?";return e+"cache="+CABLES.uuid()};const Z=function(t,n){if(!t)return null;n=n||[];n.length=t.length;for(let e=0;e<t.length;e++){n[e]=t[e]}return n};const K=function(e){let t=CABLES.filename(e);const n=t.split(".");t=n[0];return t};const Q=function(){console.log("logstack",(new Error).stack)};const q=function(e){let t="";if(!e)return"";if(e.startsWith("data:")&&e.contains(":")){const n=e.split(",");return n[0]}let n=(e+"").split("/");if(n.length>0){const i=n[n.length-1];let e=i.split("?");t=e[0]}return t||""};const J=function(e,t,n,i,r){h({url:e,cb:t,method:n,data:i,contenttype:r,sync:true})};const $=function(e,t,n,i,r,s,a={},o={}){const l={url:e,cb:t,method:n,data:i,contenttype:r,sync:false,jsonP:s,headers:a};if(o&&o.credentials)l.credentials=o.credentials;h(l)};const h=function(t){if(!t.hasOwnProperty("asynch"))t.asynch=true;let n;try{n=new XMLHttpRequest}catch(e){}n.onreadystatechange=function(){if(n.readyState!=4)return;if(t.cb){if(n.status==200||n.status==0)t.cb(false,n.responseText,n);else t.cb(true,n.responseText,n)}};try{n.open(t.method?t.method.toUpperCase():"GET",t.url,!t.sync)}catch(e){if(t.cb&&e)t.cb(true,e.msg,n)}if(typeof t.headers==="object"){if(t.headers){const i=Object.keys(t.headers);for(let e=0;e<i.length;e++){const r=i[e];const s=t.headers[r];n.setRequestHeader(r,s)}}}if(t.credentials&&t.credentials!=="omit"){n.withCredentials=true}try{if(!t.post&&!t.data){n.send()}else{n.setRequestHeader("Content-type",t.contenttype?t.contenttype:"application/x-www-form-urlencoded");n.send(t.data||t.post)}}catch(e){if(t.cb)t.cb(true,e.msg,n)}};const ee=function(e){if(!e&&e!==0)return"Unidentified";const t={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:"Space",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"};if(t[e]){return t[e]}else{return String.fromCharCode(e)}};window.performance=window.performance||{offset:Date.now(),now:function e(){return Date.now()-this.offset}};const te=function(e){CABLES.errorConsole=CABLES.errorConsole||{log:[]};CABLES.errorConsole.log.push({initiator:e,arguments:arguments});if(!CABLES.errorConsole.ele){const t=document.createElement("div");t.id="cablesErrorConsole";t.style.width="90%";t.style.height="300px";t.style.zIndex="9999999";t.style.display="inline-block";t.style.position="absolute";t.style.padding="10px";t.style.fontFamily="monospace";t.style.color="red";t.style.backgroundColor="#200";CABLES.errorConsole.ele=t;document.body.appendChild(t)}let i="ERROR<br/>for more info, open your browsers dev tools console (Ctrl+Shift+I or Command+Alt+I)<br/>";for(let n=0;n<CABLES.errorConsole.log.length;n++){i+=CABLES.errorConsole.log[n].initiator+" ";for(let e=1;e<CABLES.errorConsole.log[n].arguments.length;e++){if(e>2)i+=", ";let t=CABLES.errorConsole.log[n].arguments[e];if(t.constructor.name.indexOf("Error")>-1||t.constructor.name.indexOf("error")>-1){let e="Uncaught ErrorEvent ";if(t.message)e+=" message: "+t.message;i+=e}else if(typeof t=="string")i+=t;else if(typeof t=="number")i+=String(t)+" "}i+="<br/>"}CABLES.errorConsole.ele.innerHTML=i};class l{constructor(e){this._init();this._first=true;this._wireMesh=null;if(e)this.apply(e)}_init(){this._max=[-0,-0,-0];this._min=[0,0,0];this._center=[0,0,0];this._size=[0,0,0];this._maxAxis=0;this._first=true}get maxAxis(){return this._maxAxis||1}get size(){return this._size}get center(){return this._center}get x(){return this._center[0]}get y(){return this._center[1]}get z(){return this._center[2]}get minX(){return this._min[0]}get minY(){return this._min[1]}get minZ(){return this._min[2]}get maxX(){return this._max[0]}get maxY(){return this._max[1]}get maxZ(){return this._max[2]}apply(t,e){if(!t){return}if(t instanceof l){const n=t;this.applyPos(n.maxX,n.maxY,n.maxZ);this.applyPos(n.minX,n.minY,n.minZ)}else{for(let e=0;e<t.vertices.length;e+=3)this.applyPos(t.vertices[e],t.vertices[e+1],t.vertices[e+2])}this.calcCenterSize()}copy(){return new l(this)}get changed(){return!(this._max[0]==-Number.MAX_VALUE&&this._max[1]==-Number.MAX_VALUE&&this._max[2]==-Number.MAX_VALUE)}applyPos(e,t,n){if(e==Number.MAX_VALUE||e==-Number.MAX_VALUE||t==Number.MAX_VALUE||t==-Number.MAX_VALUE||n==Number.MAX_VALUE||n==-Number.MAX_VALUE)return;if(!CABLES.UTILS.isNumeric(e)||!CABLES.UTILS.isNumeric(t)||!CABLES.UTILS.isNumeric(n))return;if(this._first){this._max[0]=e;this._max[1]=t;this._max[2]=n;this._min[0]=e;this._min[1]=t;this._min[2]=n;this._first=false;return}this._max[0]=Math.max(this._max[0],e);this._max[1]=Math.max(this._max[1],t);this._max[2]=Math.max(this._max[2],n);this._min[0]=Math.min(this._min[0],e);this._min[1]=Math.min(this._min[1],t);this._min[2]=Math.min(this._min[2],n)}calcCenterSize(){if(this._first)return;this._size[0]=this._max[0]-this._min[0];this._size[1]=this._max[1]-this._min[1];this._size[2]=this._max[2]-this._min[2];this._center[0]=(this._min[0]+this._max[0])/2;this._center[1]=(this._min[1]+this._max[1])/2;this._center[2]=(this._min[2]+this._max[2])/2;this._maxAxis=Math.max(this._size[2],Math.max(this._size[0],this._size[1]))}mulMat4(e){if(this._first){this._max[0]=0;this._max[1]=0;this._max[2]=0;this._min[0]=0;this._min[1]=0;this._min[2]=0;this._first=false}vec3.transformMat4(this._max,this._max,e);vec3.transformMat4(this._min,this._min,e);this.calcCenterSize()}render(e,t,n){if(!this._wireMesh)this._wireMesh=new CGL.WireCube(e);e.pushModelMatrix();mat4.translate(e.mMatrix,e.mMatrix,this._center);if(CABLES.UI&&n){CABLES.UI.OverlayMeshes.drawCube(n,this._size[0]/2,this._size[1]/2,this._size[2]/2)}e.popModelMatrix()}}const f=function(e){this.name=e||"unknown";this._log=new u("cgl_geometry");this.faceVertCount=3;this.glPrimitive=null;this._attributes={};this._vertices=[];this.verticesIndices=[];this.isGeometry=true;this.morphTargets=[];Object.defineProperty(this,"vertices",{get(){return this._vertices},set(e){this.setVertices(e)}});Object.defineProperty(this,"texCoords",{get(){const e=this.getAttribute("texCoords");if(!e)return[];return e.data},set(e){this.setAttribute("texCoords",e,2)}});Object.defineProperty(this,"vertexNormals",{get(){const e=this.getAttribute("vertexNormals");if(!e)return[];return e.data},set(e){this.setAttribute("vertexNormals",e,3)}});Object.defineProperty(this,"tangents",{get(){const e=this.getAttribute("tangents");if(!e)return[];return e.data},set(e){this.setAttribute("tangents",e,3)}});Object.defineProperty(this,"biTangents",{get(){const e=this.getAttribute("biTangents");if(!e)return[];return e.data},set(e){this.setAttribute("biTangents",e,3)}});Object.defineProperty(this,"vertexColors",{get(){const e=this.getAttribute("vertexColors");if(!e)return[];return e.data},set(e){this.setAttribute("vertexColors",e,4)}})};f.prototype.clear=function(){this._vertices=new Float32Array([]);this.verticesIndices=[];this.texCoords=new Float32Array([]);this.vertexNormals=new Float32Array([]);this.tangents=[];this.biTangents=[];this._attributes={}};f.prototype.getAttributes=function(){return this._attributes};f.prototype.getAttribute=function(e){for(const t in this._attributes){if(this._attributes[t].name==e)return this._attributes[t]}return null};f.prototype.setAttribute=function(e,t,n){let i="";if(!n||n>4){console.log("itemsize wrong?",n,e);this._log.stack("itemsize");n=3}if(n==1)i="float";else if(n==2)i="vec2";else if(n==3)i="vec3";else if(n==4)i="vec4";const r={name:e,data:t,itemSize:n,type:i};this._attributes[e]=r};f.prototype.copyAttribute=function(e,t){const n=this.getAttribute(e);t.setAttribute(e,new Float32Array(n.data),n.itemSize)};f.prototype.setVertices=function(e){if(e instanceof Float32Array)this._vertices=e;else this._vertices=new Float32Array(e)};f.prototype.setTexCoords=function(e){if(e instanceof Float32Array)this.texCoords=e;else this.texCoords=new Float32Array(e)};f.prototype.calcNormals=function(e){const t={smooth:e};this.calculateNormals(t)};f.prototype.flipNormals=function(t,n,i){let r=vec3.create();if(t==undefined)t=1;if(n==undefined)n=1;if(i==undefined)i=1;for(let e=0;e<this.vertexNormals.length;e+=3){vec3.set(r,this.vertexNormals[e+0],this.vertexNormals[e+1],this.vertexNormals[e+2]);r[0]*=-t;r[1]*=-n;r[2]*=-i;vec3.normalize(r,r);this.vertexNormals[e+0]=r[0];this.vertexNormals[e+1]=r[1];this.vertexNormals[e+2]=r[2]}};f.prototype.getNumTriangles=function(){if(this.verticesIndices&&this.verticesIndices.length)return this.verticesIndices.length/3;return this.vertices.length/3};f.prototype.flipVertDir=function(){const t=[];t.length=this.verticesIndices.length;for(let e=0;e<this.verticesIndices.length;e+=3){t[e]=this.verticesIndices[e+2];t[e+1]=this.verticesIndices[e+1];t[e+2]=this.verticesIndices[e]}this.verticesIndices=t};f.prototype.setPointVertices=function(t){if(t.length%3!==0){this._log.error("SetPointVertices: Array must be multiple of three.");return}if(!(t instanceof Float32Array))this.vertices=new Float32Array(t);else this.vertices=t;if(!(this.texCoords instanceof Float32Array))this.texCoords=new Float32Array(t.length/3*2);this.verticesIndices.length=t.length/3;for(let e=0;e<t.length/3;e++){this.verticesIndices[e]=e;this.texCoords[e*2]=0;this.texCoords[e*2+1]=0}};f.prototype.merge=function(t){if(!t)return;if(this.isIndexed()!=t.isIndexed()){if(this.isIndexed()){this.unIndex(false,true)}if(t.isIndexed()){const e=t.copy();e.unIndex(false,true);t=e}}const n=this.verticesIndices.length;const i=this._vertices.length/3;this.verticesIndices.length+=t.verticesIndices.length;for(let e=0;e<t.verticesIndices.length;e++)this.verticesIndices[n+e]=t.verticesIndices[e]+i;this.vertices=r.float32Concat(this._vertices,t.vertices);this.texCoords=r.float32Concat(this.texCoords,t.texCoords);this.vertexNormals=r.float32Concat(this.vertexNormals,t.vertexNormals);this.tangents=r.float32Concat(this.tangents,t.tangents);this.biTangents=r.float32Concat(this.biTangents,t.biTangents)};f.prototype.copy=function(){const t=new f(this.name+" copy");t.faceVertCount=this.faceVertCount;t.glPrimitive=this.glPrimitive;t.setVertices(this._vertices.slice(0));if(this.verticesIndices){t.verticesIndices.length=this.verticesIndices.length;for(let e=0;e<this.verticesIndices.length;e++)t.verticesIndices[e]=this.verticesIndices[e]}for(let e in this._attributes)this.copyAttribute(e,t);t.morphTargets.length=this.morphTargets.length;for(let e=0;e<this.morphTargets.length;e++)t.morphTargets[e]=this.morphTargets[e];return t};f.prototype.calculateNormals=function(t){t=t||{};if(t.smooth===false)this.unIndex();const n=vec3.create();const i=vec3.create();const r=vec3.create();function s(e){vec3.subtract(n,e[0],e[1]);vec3.subtract(i,e[0],e[2]);vec3.cross(r,n,i);vec3.normalize(r,r);if(t&&t.forceZUp){if(r[2]<0){r[0]*=-1;r[1]*=-1;r[2]*=-1}}return r}this.getVertexVec=function(e){const t=[0,0,0];t[0]=this.vertices[e*3+0];t[1]=this.vertices[e*3+1];t[2]=this.vertices[e*3+2];return t};if(!(this.vertexNormals instanceof Float32Array)||this.vertexNormals.length!=this.vertices.length)this.vertexNormals=new Float32Array(this.vertices.length);for(let e=0;e<this.vertices.length;e++){this.vertexNormals[e]=0}if(!this.isIndexed()){const a=[];for(let e=0;e<this.vertices.length;e+=9){const o=[[this.vertices[e+0],this.vertices[e+1],this.vertices[e+2]],[this.vertices[e+3],this.vertices[e+4],this.vertices[e+5]],[this.vertices[e+6],this.vertices[e+7],this.vertices[e+8]]];const l=s(o);a.push(l[0],l[1],l[2],l[0],l[1],l[2],l[0],l[1],l[2])}this.vertexNormals=a}else{const h=[];h.length=Math.floor(this.verticesIndices.length/3);for(let e=0;e<this.verticesIndices.length;e+=3){const o=[this.getVertexVec(this.verticesIndices[e+0]),this.getVertexVec(this.verticesIndices[e+1]),this.getVertexVec(this.verticesIndices[e+2])];h[e/3]=s(o);this.vertexNormals[this.verticesIndices[e+0]*3+0]+=h[e/3][0];this.vertexNormals[this.verticesIndices[e+0]*3+1]+=h[e/3][1];this.vertexNormals[this.verticesIndices[e+0]*3+2]+=h[e/3][2];this.vertexNormals[this.verticesIndices[e+1]*3+0]+=h[e/3][0];this.vertexNormals[this.verticesIndices[e+1]*3+1]+=h[e/3][1];this.vertexNormals[this.verticesIndices[e+1]*3+2]+=h[e/3][2];this.vertexNormals[this.verticesIndices[e+2]*3+0]+=h[e/3][0];this.vertexNormals[this.verticesIndices[e+2]*3+1]+=h[e/3][1];this.vertexNormals[this.verticesIndices[e+2]*3+2]+=h[e/3][2]}for(let t=0;t<this.verticesIndices.length;t+=3){for(let e=0;e<3;e++){const u=[this.vertexNormals[this.verticesIndices[t+e]*3+0],this.vertexNormals[this.verticesIndices[t+e]*3+1],this.vertexNormals[this.verticesIndices[t+e]*3+2]];vec3.normalize(u,u);this.vertexNormals[this.verticesIndices[t+e]*3+0]=u[0];this.vertexNormals[this.verticesIndices[t+e]*3+1]=u[1];this.vertexNormals[this.verticesIndices[t+e]*3+2]=u[2]}}}};f.prototype.calcTangentsBitangents=function(){if(!this.vertices.length){return}if(!this.vertexNormals.length){return}if(!this.texCoords.length){const _=this.vertices.length/3*2;this.texCoords=new Float32Array(_);for(let e=0;e<_;e+=1)this.texCoords[e]=0}if(!this.verticesIndices||!this.verticesIndices.length){return}if(this.verticesIndices.length%3!==0){this._log.error("Vertex indices mismatch!");return}const t=this.verticesIndices.length/3;const n=this.vertices.length/3;this.tangents=new Float32Array(this.vertexNormals.length);this.biTangents=new Float32Array(this.vertexNormals.length);const i=[];i.length=n*2;const r=vec3.create();const s=vec3.create();const a=vec3.create();const o=vec2.create();const l=vec2.create();const h=vec2.create();const u=vec3.create();const f=vec3.create();for(let e=0;e<t;e+=1){const E=this.verticesIndices[e*3];const v=this.verticesIndices[e*3+1];const b=this.verticesIndices[e*3+2];vec3.set(r,this.vertices[E*3],this.vertices[E*3+1],this.vertices[E*3+2]);vec3.set(s,this.vertices[v*3],this.vertices[v*3+1],this.vertices[v*3+2]);vec3.set(a,this.vertices[b*3],this.vertices[b*3+1],this.vertices[b*3+2]);vec2.set(o,this.texCoords[E*2],this.texCoords[E*2+1]);vec2.set(l,this.texCoords[v*2],this.texCoords[v*2+1]);vec2.set(h,this.texCoords[b*2],this.texCoords[b*2+1]);const B=s[0]-r[0];const D=a[0]-r[0];const y=s[1]-r[1];const x=a[1]-r[1];const S=s[2]-r[2];const T=a[2]-r[2];const O=l[0]-o[0];const I=h[0]-o[0];const w=l[1]-o[1];const L=h[1]-o[1];const N=1/(O*L-I*w);vec3.set(u,(L*B-w*D)*N,(L*y-w*x)*N,(L*S-w*T)*N);vec3.set(f,(O*D-I*B)*N,(O*x-I*y)*N,(O*T-I*S)*N);i[E]=u;i[v]=u;i[b]=u;i[E+n]=f;i[v+n]=f;i[b+n]=f}const c=vec3.create();const d=vec3.create();const m=vec3.create();const g=vec3.create();const p=vec3.create();const F=vec3.create();const A=vec3.create();const C=vec3.create();for(let e=0;e<n;e+=1){if(!i[e])continue;vec3.set(c,this.vertexNormals[e*3],this.vertexNormals[e*3+1],this.vertexNormals[e*3+2]);vec3.set(d,i[e][0],i[e][1],i[e][2]);const R=vec3.dot(c,d);vec3.scale(p,c,R);vec3.subtract(F,d,p);vec3.normalize(C,F);vec3.cross(A,c,d);const k=1;vec3.scale(m,C,1/k);vec3.cross(g,c,m);this.tangents[e*3+0]=m[0];this.tangents[e*3+1]=m[1];this.tangents[e*3+2]=m[2];this.biTangents[e*3+0]=g[0];this.biTangents[e*3+1]=g[1];this.biTangents[e*3+2]=g[2]}};f.prototype.isIndexed=function(){if(this._vertices.length==0)return true;return this.verticesIndices.length!=0};f.prototype.unIndex=function(e,t){const n=[];const i=[];let r=0;for(let e in this._attributes){const s=this._attributes[e];let n=[];for(let t=0;t<this.verticesIndices.length;t+=3){for(let e=0;e<3;e++){if(s.itemSize==3)n.push(s.data[this.verticesIndices[t+e]*3+0],s.data[this.verticesIndices[t+e]*3+1],s.data[this.verticesIndices[t+e]*3+2]);else if(s.itemSize==4)n.push(s.data[this.verticesIndices[t+e]*4+0],s.data[this.verticesIndices[t+e]*4+1],s.data[this.verticesIndices[t+e]*4+2],s.data[this.verticesIndices[t+e]*4+3]);else if(s.itemSize==2)n.push(s.data[this.verticesIndices[t+e]*2+0],s.data[this.verticesIndices[t+e]*2+1]);else if(s.itemSize==1)n.push(s.data[this.verticesIndices[t+e]]);else console.log("unknown attr",s)}}this.setAttribute(s.name,n,s.itemSize)}for(let e=0;e<this.verticesIndices.length;e+=3){n.push(this.vertices[this.verticesIndices[e+0]*3+0],this.vertices[this.verticesIndices[e+0]*3+1],this.vertices[this.verticesIndices[e+0]*3+2]);i.push(r);r++;n.push(this.vertices[this.verticesIndices[e+1]*3+0],this.vertices[this.verticesIndices[e+1]*3+1],this.vertices[this.verticesIndices[e+1]*3+2]);i.push(r);r++;n.push(this.vertices[this.verticesIndices[e+2]*3+0],this.vertices[this.verticesIndices[e+2]*3+1],this.vertices[this.verticesIndices[e+2]*3+2]);i.push(r);r++}this.vertices=n;this.verticesIndices=[];if(e)this.verticesIndices=i;if(!t)this.calculateNormals()};f.prototype.calcBarycentric=function(){let t=[];t.length=this.vertices.length;for(let e=0;e<this.vertices.length;e++)t[e]=0;let n=0;for(let e=0;e<this.vertices.length;e+=3){t[e+n]=1;n++;if(n==3)n=0}this.setAttribute("attrBarycentric",t,3)};f.prototype.getBounds=function(){return new l(this)};f.prototype.center=function(e,t,n){if(e===undefined){e=true;t=true;n=true}let i=0;const r=this.getBounds();const s=[r.minX+(r.maxX-r.minX)/2,r.minY+(r.maxY-r.minY)/2,r.minZ+(r.maxZ-r.minZ)/2];for(i=0;i<this.vertices.length;i+=3){if(this.vertices[i+0]==this.vertices[i+0]){if(e)this.vertices[i+0]-=s[0];if(t)this.vertices[i+1]-=s[1];if(n)this.vertices[i+2]-=s[2]}}return s};f.prototype.mapTexCoords2d=function(){const t=this.getBounds();const n=this.vertices.length/3;this.texCoords=new Float32Array(n*2);for(let e=0;e<n;e++){const i=this.vertices[e*3+0];const r=this.vertices[e*3+1];this.texCoords[e*2+0]=i/(t.maxX-t.minX)+.5;this.texCoords[e*2+1]=1-r/(t.maxY-t.minY)+.5}};f.prototype.getInfoOneLine=function(){let e="";if(this.faceVertCount==3&&this.verticesIndices)e+=this.verticesIndices.length/3;else e+=0;e+=" tris ";if(this.vertices)e+=this.vertices.length/3;else e+=0;e+=" verts";return e};f.prototype.getInfo=function(){const e={};if(this.faceVertCount==3&&this.verticesIndices)e.numFaces=this.verticesIndices.length/3;else e.numFaces=0;if(this.verticesIndices&&this.verticesIndices.length)e.indices=this.verticesIndices.length;if(this.vertices)e.numVerts=this.vertices.length/3;else e.numVerts=0;if(this.vertexNormals)e.numNormals=this.vertexNormals.length/3;else e.numNormals=0;if(this.texCoords)e.numTexCoords=this.texCoords.length/2;else e.numTexCoords=0;if(this.tangents)e.numTangents=this.tangents.length/3;else e.numTangents=0;if(this.biTangents)e.numBiTangents=this.biTangents.length/3;else e.numBiTangents=0;if(this.biTangents)e.numBiTangents=this.biTangents.length/3;else e.numBiTangents=0;if(this.vertexColors)e.numVertexColors=this.vertexColors.length/4;else e.numVertexColors=0;if(this.getAttributes())e.numAttribs=Object.keys(this.getAttributes()).length;else e.numAttribs=0;e.isIndexed=this.isIndexed();return e};f.buildFromFaces=function(t,e,n){const i=[];const r=[];for(let e=0;e<t.length;e+=3){const a=t[e+0];const o=t[e+1];const l=t[e+2];const h=[-1,-1,-1];if(n)for(let e=0;e<i.length;e+=3){if(i[e+0]==a[0]&&i[e+1]==a[1]&&i[e+2]==a[2])h[0]=e/3;if(i[e+0]==o[0]&&i[e+1]==o[1]&&i[e+2]==o[2])h[1]=e/3;if(i[e+0]==l[0]&&i[e+1]==l[1]&&i[e+2]==l[2])h[2]=e/3}if(h[0]==-1){i.push(a[0],a[1],a[2]);h[0]=(i.length-1)/3}if(h[1]==-1){i.push(o[0],o[1],o[2]);h[1]=(i.length-1)/3}if(h[2]==-1){i.push(l[0],l[1],l[2]);h[2]=(i.length-1)/3}r.push(parseInt(h[0],10));r.push(parseInt(h[1],10));r.push(parseInt(h[2],10))}const s=new f(e);s.name=e;s.vertices=i;s.verticesIndices=r;return s};const c=function(){this._log=new u("eventtarget");this._eventCallbacks={};this._logName="";this._logEvents=false;this._listeners={};this.addEventListener=this.on=function(e,t,n){const i={id:(n||"")+CABLES.simpleId(),name:e,cb:t};if(!this._eventCallbacks[e])this._eventCallbacks[e]=[i];else this._eventCallbacks[e].push(i);this._listeners[i.id]=i;return i.id};this.hasEventListener=function(e,t){if(e&&!t){if(this._listeners[e])return true;else return false}else{this._log.warn("old eventtarget function haseventlistener!");if(e&&t){if(this._eventCallbacks[e]){const n=this._eventCallbacks[e].indexOf(t);if(n==-1)return false;return true}}}};this.hasListenerForEventName=function(e){return this._eventCallbacks[e]&&this._eventCallbacks[e].length>0};this.removeEventListener=this.off=function(i,t){if(i===null||i===undefined)return;if(!t){const r=this._listeners[i];if(!r){this._log.log("removeEvent: could not find event...",i,this);return}let n=true;while(n){n=false;let t=-1;for(let e=0;e<this._eventCallbacks[r.name].length;e++){if(this._eventCallbacks[r.name][e].id.startsWith(i)){n=true;t=e}}if(t!==-1){this._eventCallbacks[r.name].splice(t,1);delete this._listeners[i]}}return}this._log.info("[eventtaget] ","old function signature: removeEventListener! use listener id");this._log.log((new Error).stack);let n=null;for(let e=0;e<this._eventCallbacks[i].length;e++)if(this._eventCallbacks[i][e].cb==t)n=e;if(n!==null){delete this._eventCallbacks[n]}else this._log.warn("removeEventListener not found "+i)};this.logEvents=function(e,t){this._logEvents=e;this._logName=t};this.emitEvent=function(t,n,i,r,s,a,o){if(this._logEvents)this._log.log("[event] ",this._logName,t,this._eventCallbacks);if(this._eventCallbacks[t]){for(let e=0;e<this._eventCallbacks[t].length;e++){if(this._eventCallbacks[t][e]){this._eventCallbacks[t][e].cb(n,i,r,s,a,o)}}}else{if(this._logEvents)this._log.log("[event] has no event callback",t,this._eventCallbacks)}}};const d={ANIM:{EASINGS:["linear","absolute","smoothstep","smootherstep","Cubic In","Cubic Out","Cubic In Out","Expo In","Expo Out","Expo In Out","Sin In","Sin Out","Sin In Out","Quart In","Quart Out","Quart In Out","Quint In","Quint Out","Quint In Out","Back In","Back Out","Back In Out","Elastic In","Elastic Out","Bounce In","Bounce Out"],EASING_LINEAR:0,EASING_ABSOLUTE:1,EASING_SMOOTHSTEP:2,EASING_SMOOTHERSTEP:3,EASING_CUBICSPLINE:4,EASING_CUBIC_IN:5,EASING_CUBIC_OUT:6,EASING_CUBIC_INOUT:7,EASING_EXPO_IN:8,EASING_EXPO_OUT:9,EASING_EXPO_INOUT:10,EASING_SIN_IN:11,EASING_SIN_OUT:12,EASING_SIN_INOUT:13,EASING_BACK_IN:14,EASING_BACK_OUT:15,EASING_BACK_INOUT:16,EASING_ELASTIC_IN:17,EASING_ELASTIC_OUT:18,EASING_BOUNCE_IN:19,EASING_BOUNCE_OUT:21,EASING_QUART_IN:22,EASING_QUART_OUT:23,EASING_QUART_INOUT:24,EASING_QUINT_IN:25,EASING_QUINT_OUT:26,EASING_QUINT_INOUT:27},OP:{OP_PORT_TYPE_VALUE:0,OP_PORT_TYPE_NUMBER:0,OP_PORT_TYPE_FUNCTION:1,OP_PORT_TYPE_TRIGGER:1,OP_PORT_TYPE_OBJECT:2,OP_PORT_TYPE_TEXTURE:2,OP_PORT_TYPE_ARRAY:3,OP_PORT_TYPE_DYNAMIC:4,OP_PORT_TYPE_STRING:5,OP_VERSION_PREFIX:"_v"},PORT:{PORT_DIR_IN:0,PORT_DIR_OUT:1},PACO:{PACO_CLEAR:0,PACO_VALUECHANGE:1,PACO_OP_DELETE:2,PACO_UNLINK:3,PACO_LINK:4,PACO_LOAD:5,PACO_OP_CREATE:6,PACO_OP_ENABLE:7,PACO_OP_DISABLE:8,PACO_UIATTRIBS:9,PACO_VARIABLES:10,PACO_TRIGGERS:11,PACO_PORT_SETVARIABLE:12,PACO_PORT_SETANIMATED:13,PACO_PORT_ANIM_UPDATED:14,PACO_DESERIALIZE:15,PACO_OP_RELOAD:16}};const m=function(e){this.time=0;this.value=0;this.onChange=null;this._easing=0;this.cb=null;this.cbTriggered=false;this.setEasing(d.ANIM.EASING_LINEAR);this.set(e)};m.cubicSpline=function(e,t,n){let i=t.value,r=t.bezTangOut,s=n.value,a=n.bezTangIn;let o=e;let l=o*o;let h=l*o;return(2*h-3*l+1)*i+(h-2*l+o)*r+(-2*h+3*l)*s+(h-l)*a};m.easeCubicSpline=function(e,t){return m.cubicSpline(e,this,t)};m.linear=function(e,t,n){return parseFloat(t.value)+parseFloat(n.value-t.value)*e};m.easeLinear=function(e,t){return m.linear(e,this,t)};m.easeAbsolute=function(e,t){return this.value};const g=function(e){return e=2**(10*(e-1))};m.easeExpoIn=function(e,t){e=g(e);return m.linear(e,this,t)};const p=function(e){e=-(2**(-10*e))+1;return e};m.easeExpoOut=function(e,t){e=p(e);return m.linear(e,this,t)};const F=function(e){e*=2;if(e<1){e=.5*2**(10*(e-1))}else{e--;e=.5*(-(2**(-10*e))+2)}return e};m.easeExpoInOut=function(e,t){e=F(e);return m.linear(e,this,t)};m.easeSinIn=function(e,t){e=-1*Math.cos(e*Math.PI/2)+1;return m.linear(e,this,t)};m.easeSinOut=function(e,t){e=Math.sin(e*Math.PI/2);return m.linear(e,this,t)};m.easeSinInOut=function(e,t){e=-.5*(Math.cos(Math.PI*e)-1);return m.linear(e,this,t)};const A=function(e){e=e*e*e;return e};m.easeCubicIn=function(e,t){e=A(e);return m.linear(e,this,t)};m.easeInQuint=function(e,t){e=e*e*e*e*e;return m.linear(e,this,t)};m.easeOutQuint=function(e,t){e=(e-=1)*e*e*e*e+1;return m.linear(e,this,t)};m.easeInOutQuint=function(e,t){if((e/=.5)<1)e=.5*e*e*e*e*e;else e=.5*((e-=2)*e*e*e*e+2);return m.linear(e,this,t)};m.easeInQuart=function(e,t){e=e*e*e*e;return m.linear(e,this,t)};m.easeOutQuart=function(e,t){e=-1*((e-=1)*e*e*e-1);return m.linear(e,this,t)};m.easeInOutQuart=function(e,t){if((e/=.5)<1)e=.5*e*e*e*e;else e=-.5*((e-=2)*e*e*e-2);return m.linear(e,this,t)};m.bounce=function(e){if((e/=1)<1/2.75)e=7.5625*e*e;else if(e<2/2.75)e=7.5625*(e-=1.5/2.75)*e+.75;else if(e<2.5/2.75)e=7.5625*(e-=2.25/2.75)*e+.9375;else e=7.5625*(e-=2.625/2.75)*e+.984375;return e};m.easeInBounce=function(e,t){return m.linear(m.bounce(e),this,t)};m.easeOutBounce=function(e,t){return m.linear(m.bounce(e),this,t)};m.easeInElastic=function(e,t){let n=1.70158;let i=0;let r=1;const s=0;const a=1;const o=1;if(e===0)e=s;else if((e/=a)==1)e=s+o;else{if(!i)i=a*.3;if(r<Math.abs(o)){r=o;n=i/4}else n=i/(2*Math.PI)*Math.asin(o/r);e=-(r*2**(10*(e-=1))*Math.sin((e*a-n)*(2*Math.PI)/i))+s}return m.linear(e,this,t)};m.easeOutElastic=function(e,t){let n=1.70158;let i=0;let r=1;const s=0;const a=1;const o=1;if(e===0)e=s;else if((e/=a)==1)e=s+o;else{if(!i)i=a*.3;if(r<Math.abs(o)){r=o;n=i/4}else n=i/(2*Math.PI)*Math.asin(o/r);e=r*2**(-10*e)*Math.sin((e*a-n)*(2*Math.PI)/i)+o+s}return m.linear(e,this,t)};m.easeInBack=function(e,t){const n=1.70158;e=e*e*((n+1)*e-n);return m.linear(e,this,t)};m.easeOutBack=function(e,t){const n=1.70158;e=(e=e/1-1)*e*((n+1)*e+n)+1;return m.linear(e,this,t)};m.easeInOutBack=function(e,t){let n=1.70158;const i=1/2;if((e/=1/2)<1)e=i*(e*e*(((n*=1.525)+1)*e-n));else e=i*((e-=2)*e*(((n*=1.525)+1)*e+n)+2);return m.linear(e,this,t)};const C=function(e){e--;e=e*e*e+1;return e};m.easeCubicOut=function(e,t){e=C(e);return m.linear(e,this,t)};const _=function(e){e*=2;if(e<1)e=.5*e*e*e;else{e-=2;e=.5*(e*e*e+2)}return e};m.easeCubicInOut=function(e,t){e=_(e);return m.linear(e,this,t)};m.easeSmoothStep=function(e,t){const n=Math.max(0,Math.min(1,e));e=n*n*(3-2*n);return m.linear(e,this,t)};m.easeSmootherStep=function(e,t){const n=Math.max(0,Math.min(1,(e-0)/(1-0)));e=n*n*n*(n*(n*6-15)+10);return m.linear(e,this,t)};m.prototype.setEasing=function(e){this._easing=e;if(this._easing==d.ANIM.EASING_LINEAR)this.ease=m.easeLinear;else if(this._easing==d.ANIM.EASING_ABSOLUTE)this.ease=m.easeAbsolute;else if(this._easing==d.ANIM.EASING_SMOOTHSTEP)this.ease=m.easeSmoothStep;else if(this._easing==d.ANIM.EASING_SMOOTHERSTEP)this.ease=m.easeSmootherStep;else if(this._easing==d.ANIM.EASING_CUBIC_IN)this.ease=m.easeCubicIn;else if(this._easing==d.ANIM.EASING_CUBIC_OUT)this.ease=m.easeCubicOut;else if(this._easing==d.ANIM.EASING_CUBIC_INOUT)this.ease=m.easeCubicInOut;else if(this._easing==d.ANIM.EASING_EXPO_IN)this.ease=m.easeExpoIn;else if(this._easing==d.ANIM.EASING_EXPO_OUT)this.ease=m.easeExpoOut;else if(this._easing==d.ANIM.EASING_EXPO_INOUT)this.ease=m.easeExpoInOut;else if(this._easing==d.ANIM.EASING_SIN_IN)this.ease=m.easeSinIn;else if(this._easing==d.ANIM.EASING_SIN_OUT)this.ease=m.easeSinOut;else if(this._easing==d.ANIM.EASING_SIN_INOUT)this.ease=m.easeSinInOut;else if(this._easing==d.ANIM.EASING_BACK_OUT)this.ease=m.easeOutBack;else if(this._easing==d.ANIM.EASING_BACK_IN)this.ease=m.easeInBack;else if(this._easing==d.ANIM.EASING_BACK_INOUT)this.ease=m.easeInOutBack;else if(this._easing==d.ANIM.EASING_ELASTIC_IN)this.ease=m.easeInElastic;else if(this._easing==d.ANIM.EASING_ELASTIC_OUT)this.ease=m.easeOutElastic;else if(this._easing==d.ANIM.EASING_ELASTIC_INOUT)this.ease=m.easeElasticInOut;else if(this._easing==d.ANIM.EASING_BOUNCE_IN)this.ease=m.easeInBounce;else if(this._easing==d.ANIM.EASING_BOUNCE_OUT)this.ease=m.easeOutBounce;else if(this._easing==d.ANIM.EASING_QUART_OUT)this.ease=m.easeOutQuart;else if(this._easing==d.ANIM.EASING_QUART_IN)this.ease=m.easeInQuart;else if(this._easing==d.ANIM.EASING_QUART_INOUT)this.ease=m.easeInOutQuart;else if(this._easing==d.ANIM.EASING_QUINT_OUT)this.ease=m.easeOutQuint;else if(this._easing==d.ANIM.EASING_QUINT_IN)this.ease=m.easeInQuint;else if(this._easing==d.ANIM.EASING_QUINT_INOUT)this.ease=m.easeInOutQuint;else if(this._easing==d.ANIM.EASING_CUBICSPLINE){this.ease=m.easeCubicSpline}else{this._easing=d.ANIM.EASING_LINEAR;this.ease=m.easeLinear}};m.prototype.trigger=function(){this.cb();this.cbTriggered=true};m.prototype.setValue=function(e){this.value=e;if(this.onChange!==null)this.onChange()};m.prototype.set=function(e){if(e){if(e.e)this.setEasing(e.e);if(e.cb){this.cb=e.cb;this.cbTriggered=false}if(e.b){}if(e.hasOwnProperty("t"))this.time=e.t;if(e.hasOwnProperty("time"))this.time=e.time;if(e.hasOwnProperty("v"))this.value=e.v;else if(e.hasOwnProperty("value"))this.value=e.value}if(this.onChange!==null)this.onChange()};m.prototype.getSerialized=function(){const e={};e.t=this.time;e.v=this.value;e.e=this._easing;return e};m.prototype.getEasing=function(){return this._easing};const E=function(e){c.apply(this);e=e||{};this.keys=[];this.onChange=null;this.stayInTimeline=false;this.loop=false;this._log=new u("Anim");this._lastKeyIndex=0;this._cachedIndex=0;this.name=e.name||null;this.defaultEasing=e.defaultEasing||d.ANIM.EASING_LINEAR;this.onLooped=null;this._timesLooped=0;this._needsSort=false};E.prototype.forceChangeCallback=function(){if(this.onChange!==null)this.onChange();this.emitEvent("onChange",this)};E.prototype.getLoop=function(){return this.loop};E.prototype.setLoop=function(e){this.loop=e;this.emitEvent("onChange",this)};E.prototype.hasEnded=function(e){if(this.keys.length===0)return true;if(this.keys[this._lastKeyIndex].time<=e)return true;return false};E.prototype.isRising=function(e){if(this.hasEnded(e))return false;const t=this.getKeyIndex(e);if(this.keys[t].value<this.keys[t+1].value)return true;return false};E.prototype.clearBefore=function(e){const t=this.getValue(e);const n=this.getKeyIndex(e);this.setValue(e,t);if(n>1)this.keys.splice(0,n);this._updateLastIndex()};E.prototype.clear=function(e){let t=0;if(e)t=this.getValue(e);this.keys.length=0;this._updateLastIndex();if(e)this.setValue(e,t);if(this.onChange!==null)this.onChange();this.emitEvent("onChange",this)};E.prototype.sortKeys=function(){this.keys.sort((e,t)=>{return parseFloat(e.time)-parseFloat(t.time)});this._updateLastIndex();this._needsSort=false;if(this.keys.length%1e3==0)console.log(this.name,this.keys.length)};E.prototype.getLength=function(){if(this.keys.length===0)return 0;return this.keys[this.keys.length-1].time};E.prototype.getKeyIndex=function(t){let n=0;let i=0;if(this._cachedIndex&&this.keys.length>this._cachedIndex&&t>=this.keys[this._cachedIndex].time)i=this._cachedIndex;for(let e=i;e<this.keys.length;e++){if(t>=this.keys[e].time)n=e;if(this.keys[e].time>t){if(t!=0)this._cachedIndex=n;return n}}return n};E.prototype.setValue=function(t,n,i){let r=null;if(this.keys.length==0||t<=this.keys[this.keys.length-1].time)for(let e=0;e<this.keys.length;e++)if(this.keys[e].time==t){r=this.keys[e];this.keys[e].setValue(n);this.keys[e].cb=i;break}if(!r){r=new m({time:t,value:n,e:this.defaultEasing,cb:i});this.keys.push(r);this._updateLastIndex()}if(this.onChange)this.onChange();this.emitEvent("onChange",this);this._needsSort=true;return r};E.prototype.setKeyEasing=function(e,t){if(this.keys[e]){this.keys[e].setEasing(t);this.emitEvent("onChange",this)}};E.prototype.getSerialized=function(){const t={};t.keys=[];t.loop=this.loop;for(let e=0;e<this.keys.length;e++)t.keys.push(this.keys[e].getSerialized());return t};E.prototype.getKey=function(e){const t=this.getKeyIndex(e);return this.keys[t]};E.prototype.getNextKey=function(e){let t=this.getKeyIndex(e)+1;if(t>=this.keys.length)t=this.keys.length-1;return this.keys[t]};E.prototype.isFinished=function(e){if(this.keys.length<=0)return true;return e>this.keys[this.keys.length-1].time};E.prototype.isStarted=function(e){if(this.keys.length<=0)return false;return e>=this.keys[0].time};E.prototype.getValue=function(e){if(this.keys.length===0){return 0}if(this._needsSort)this.sortKeys();if(!this.loop&&e>this.keys[this._lastKeyIndex].time){if(this.keys[this._lastKeyIndex].cb&&!this.keys[this._lastKeyIndex].cbTriggered)this.keys[this._lastKeyIndex].trigger();return this.keys[this._lastKeyIndex].value}if(e<this.keys[0].time){return this.keys[0].value}if(this.loop&&e>this.keys[this._lastKeyIndex].time){const a=e/this.keys[this._lastKeyIndex].time;if(a>this._timesLooped){this._timesLooped++;if(this.onLooped)this.onLooped()}e=(e-this.keys[0].time)%(this.keys[this._lastKeyIndex].time-this.keys[0].time);e+=this.keys[0].time}const t=this.getKeyIndex(e);if(t>=this._lastKeyIndex){if(this.keys[this._lastKeyIndex].cb&&!this.keys[this._lastKeyIndex].cbTriggered)this.keys[this._lastKeyIndex].trigger();return this.keys[this._lastKeyIndex].value}const n=t+1;const i=this.keys[t];const r=this.keys[n];if(i.cb&&!i.cbTriggered)i.trigger();if(!r)return-1;const s=(e-i.time)/(r.time-i.time);if(!i.ease)this.log._warn("has no ease",i,r);return i.ease(s,r)};E.prototype._updateLastIndex=function(){this._lastKeyIndex=this.keys.length-1};E.prototype.addKey=function(e){if(e.time===undefined){this.log.warn("key time undefined, ignoring!")}else{this.keys.push(e);if(this.onChange!==null)this.onChange();this.emitEvent("onChange",this)}this._updateLastIndex()};E.prototype.easingFromString=function(e){if(e=="linear")return d.ANIM.EASING_LINEAR;if(e=="absolute")return d.ANIM.EASING_ABSOLUTE;if(e=="smoothstep")return d.ANIM.EASING_SMOOTHSTEP;if(e=="smootherstep")return d.ANIM.EASING_SMOOTHERSTEP;if(e=="Cubic In")return d.ANIM.EASING_CUBIC_IN;if(e=="Cubic Out")return d.ANIM.EASING_CUBIC_OUT;if(e=="Cubic In Out")return d.ANIM.EASING_CUBIC_INOUT;if(e=="Expo In")return d.ANIM.EASING_EXPO_IN;if(e=="Expo Out")return d.ANIM.EASING_EXPO_OUT;if(e=="Expo In Out")return d.ANIM.EASING_EXPO_INOUT;if(e=="Sin In")return d.ANIM.EASING_SIN_IN;if(e=="Sin Out")return d.ANIM.EASING_SIN_OUT;if(e=="Sin In Out")return d.ANIM.EASING_SIN_INOUT;if(e=="Back In")return d.ANIM.EASING_BACK_IN;if(e=="Back Out")return d.ANIM.EASING_BACK_OUT;if(e=="Back In Out")return d.ANIM.EASING_BACK_INOUT;if(e=="Elastic In")return d.ANIM.EASING_ELASTIC_IN;if(e=="Elastic Out")return d.ANIM.EASING_ELASTIC_OUT;if(e=="Bounce In")return d.ANIM.EASING_BOUNCE_IN;if(e=="Bounce Out")return d.ANIM.EASING_BOUNCE_OUT;if(e=="Quart Out")return d.ANIM.EASING_QUART_OUT;if(e=="Quart In")return d.ANIM.EASING_QUART_IN;if(e=="Quart In Out")return d.ANIM.EASING_QUART_INOUT;if(e=="Quint Out")return d.ANIM.EASING_QUINT_OUT;if(e=="Quint In")return d.ANIM.EASING_QUINT_IN;if(e=="Quint In Out")return d.ANIM.EASING_QUINT_INOUT};E.prototype.createPort=function(e,t,n){const i=e.inDropDown(t,d.ANIM.EASINGS,"Cubic Out");i.set("linear");i.defaultValue="linear";i.onChange=function(){this.defaultEasing=this.easingFromString(i.get());this.emitEvent("onChangeDefaultEasing",this);if(n)n()}.bind(this);return i};E.slerpQuaternion=function(e,t,n,i,r,s){if(!E.slerpQuaternion.q1){E.slerpQuaternion.q1=quat.create();E.slerpQuaternion.q2=quat.create()}const a=n.getKeyIndex(e);let o=a+1;if(o>=n.keys.length)o=n.keys.length-1;if(a==o){quat.set(t,n.keys[a].value,i.keys[a].value,r.keys[a].value,s.keys[a].value)}else{const l=n.keys[a].time;const h=n.keys[o].time;const u=(e-l)/(h-l);quat.set(E.slerpQuaternion.q1,n.keys[a].value,i.keys[a].value,r.keys[a].value,s.keys[a].value);quat.set(E.slerpQuaternion.q2,n.keys[o].value,i.keys[o].value,r.keys[o].value,s.keys[o].value);quat.slerp(t,E.slerpQuaternion.q1,E.slerpQuaternion.q2,u)}return t};const v={Key:m};const b=function(e,t,n,i){c.apply(this);this.data={};this._log=new u("core_port");this.direction=d.PORT.PORT_DIR_IN;this.id=String(CABLES.simpleId());this._op=e;this.links=[];this.value=0;this.name=t;this.type=n||d.OP.OP_PORT_TYPE_VALUE;this.uiAttribs=i||{};this.anim=null;this._oldAnimVal=-5711;this.defaultValue=null;this._uiActiveState=true;this.ignoreValueSerialize=false;this.onLinkChanged=null;this.crashed=false;this._valueBeforeLink=null;this._lastAnimFrame=-1;this._animated=false;this.onValueChanged=null;this.onTriggered=null;this.onUiActiveStateChange=null;this.changeAlways=false;this.forceRefChange=false;this._useVariableName=null;this.activityCounter=0;this.apf=0;this.activityCounterStartFrame=0;this._tempLastUiValue=null;Object.defineProperty(this,"title",{get(){return this.uiAttribs.title||this.name}});Object.defineProperty(this,"parent",{get(){this._log.stack("use port.op, not .parent");return this._op}});Object.defineProperty(this,"op",{get(){return this._op}});Object.defineProperty(this,"val",{get(){return this.get()},set(e){this.setValue(e)}})};b.prototype.copyLinkedUiAttrib=function(e,t){if(!CABLES.UI)return;if(!this.isLinked())return;const n={};n[e]=this.links[0].getOtherPort(this).getUiAttrib(e);t.setUiAttribs(n)};b.prototype.getValueForDisplay=function(){let e=this.value;if(typeof this.value==="string"||this.value instanceof String){if(e.length>1e3){e=e.substring(0,999);e+="..."}if(this.uiAttribs&&this.uiAttribs.display=="boolnum"){e+=" - ";if(!this.value)e+="false";else e+="true"}e=e.replace(/[\u00A0-\u9999<>\&]/g,function(e){return"&#"+e.charCodeAt(0)+";"});if(e.length>100)e=e.substring(0,100)}else{e=this.value}return e};b.prototype.onAnimToggle=function(){};b.prototype._onAnimToggle=function(){this.onAnimToggle()};b.prototype.remove=function(){this.removeLinks();this._op.removePort(this)};b.prototype.setUiAttribs=function(e){let t=false;if(!this.uiAttribs)this.uiAttribs={};for(const n in e){if(e[n]===undefined){delete this.uiAttribs[n];continue}if(this.uiAttribs[n]!=e[n])t=true;this.uiAttribs[n]=e[n];if(n=="group"&&this.indexPort)this.indexPort.setUiAttribs({group:e[n]})}if(e.hasOwnProperty("expose"))this._op.patch.emitEvent("subpatchExpose",this._op.uiAttribs.subPatch);if(t)this.emitEvent("onUiAttrChange",e,this)};b.prototype.getUiAttribs=function(){return this.uiAttribs};b.prototype.getUiAttrib=function(e){if(!this.uiAttribs||!this.uiAttribs.hasOwnProperty(e)){return null}return this.uiAttribs[e]};b.prototype.get=function(){if(this._animated&&this._lastAnimFrame!=this._op.patch.getFrameNum()){this._lastAnimFrame=this._op.patch.getFrameNum();let e=this.anim.getValue(this._op.patch.timer.getTime());if(this.value!=e){this.value=e;this._oldAnimVal=this.value;this.forceChange()}}return this.value};b.prototype.setRef=function(e){this.forceRefChange=true;this.set(e)};b.prototype.set=b.prototype.setValue=function(e){if(e===undefined)e=null;if(CABLES.UI&&CABLES.UI.showDevInfos)if(this.direction==d.PORT.PORT_DIR_OUT&&this.type==d.OP.OP_PORT_TYPE_OBJECT&&e&&!this.forceRefChange)this._log.warn("object port uses .set",this.name,this.op.objName);if(this._op.enabled&&!this.crashed){if(e!==this.value||this.changeAlways||this.type==d.OP.OP_PORT_TYPE_TEXTURE||this.type==d.OP.OP_PORT_TYPE_ARRAY){if(this._animated){this.anim.setValue(this._op.patch.timer.getTime(),e)}else{try{this.value=e;this.forceChange()}catch(e){this.crashed=true;this.setValue=function(e){};this.onTriggered=function(){};this._log.error("exception in ",this._op);this._log.error(e);this._op.patch.emitEvent("exception",e,this._op)}if(this._op&&this._op.patch&&this._op.patch.isEditorMode()&&this.type==d.OP.OP_PORT_TYPE_TEXTURE)gui.texturePreview().updateTexturePort(this)}if(this.direction==d.PORT.PORT_DIR_OUT)for(let e=0;e<this.links.length;++e)this.links[e].setValue()}}};b.prototype.updateAnim=function(){if(this._animated){this.value=this.get();if(this._oldAnimVal!=this.value||this.changeAlways){this._oldAnimVal=this.value;this.forceChange()}this._oldAnimVal=this.value}};b.prototype.forceChange=function(){if(this.onValueChanged||this.onChange){}this._activity();this.emitEvent("change",this.value,this);if(this.onChange)this.onChange(this,this.value);else if(this.onValueChanged)this.onValueChanged(this,this.value)};b.prototype.getTypeString=function(){if(this.type==d.OP.OP_PORT_TYPE_VALUE)return"Number";if(this.type==d.OP.OP_PORT_TYPE_FUNCTION)return"Trigger";if(this.type==d.OP.OP_PORT_TYPE_OBJECT)return"Object";if(this.type==d.OP.OP_PORT_TYPE_DYNAMIC)return"Dynamic";if(this.type==d.OP.OP_PORT_TYPE_ARRAY)return"Array";if(this.type==d.OP.OP_PORT_TYPE_STRING)return"String";return"Unknown"};b.prototype.deSerializeSettings=function(e){if(!e)return;if(e.animated)this.setAnimated(e.animated);if(e.useVariable)this.setVariableName(e.useVariable);if(e.title)this.setUiAttribs({title:e.title});if(e.expose)this.setUiAttribs({expose:true});if(e.order)this.setUiAttribs({order:e.order});if(e.multiPortManual)this.setUiAttribs({multiPortManual:e.multiPortManual});if(e.multiPortNum)this.setUiAttribs({multiPortNum:e.multiPortNum});if(e.anim){if(!this.anim)this.anim=new E({name:"port "+this.name});this._op._hasAnimPort=true;this.anim.addEventListener("onChange",()=>{this._op.patch.emitEvent("portAnimUpdated",this._op,this,this.anim)});if(e.anim.loop)this.anim.loop=e.anim.loop;for(const t in e.anim.keys){this.anim.keys.push(new v.Key(e.anim.keys[t]))}this.anim.sortKeys()}};b.prototype.setInitialValue=function(e){if(this.op.preservedPortLinks[this.name]){for(let e=0;e<this.op.preservedPortLinks[this.name].length;e++){const t=this.op.preservedPortLinks[this.name][e];this.op.patch._addLink(t.objIn,t.objOut,t.portIn,t.portOut)}}if(this.op.preservedPortValues&&this.op.preservedPortValues.hasOwnProperty(this.name)&&this.op.preservedPortValues[this.name]!==undefined){this.set(this.op.preservedPortValues[this.name])}else if(e!==undefined)this.set(e);if(e!==undefined)this.defaultValue=e};b.prototype.getSerialized=function(){let e={name:this.getName()};if(!this.ignoreValueSerialize&&this.links.length===0){if(this.type==d.OP.OP_PORT_TYPE_OBJECT&&this.value&&this.value.tex){}else e.value=this.value}if(this._useVariableName)e.useVariable=this._useVariableName;if(this._animated)e.animated=true;if(this.anim)e.anim=this.anim.getSerialized();if(this.uiAttribs.multiPortNum)e.multiPortNum=this.uiAttribs.multiPortNum;if(this.uiAttribs.multiPortManual)e.multiPortManual=this.uiAttribs.multiPortManual;if(this.uiAttribs.display=="file")e.display=this.uiAttribs.display;if(this.uiAttribs.expose){e.expose=true;if(this.uiAttribs.hasOwnProperty("order"))e.order=this.uiAttribs.order}if(this.uiAttribs.title)e.title=this.uiAttribs.title;if((this.preserveLinks||this.direction==d.PORT.PORT_DIR_OUT)&&this.links.length>0){e.links=[];for(const t in this.links){if(!this.links[t].ignoreInSerialize&&(this.links[t].portIn&&this.links[t].portOut))e.links.push(this.links[t].getSerialized())}}if(this.direction==d.PORT.PORT_DIR_IN&&this.links.length>0){for(const t in this.links){if(!this.links[t].portIn||!this.links[t].portOut)continue;const n=this.links[t].getOtherPort(this);if(n.op.isInBlueprint2&&this.op.isInBlueprint2){if(n.op.isInBlueprint2()&&!this.op.isInBlueprint2()){e.links=e.links||[];e.links.push(this.links[t].getSerialized())}}}}if(e.links&&e.links.length==0)delete e.links;if(this.type===d.OP.OP_PORT_TYPE_FUNCTION)delete e.value;if(this.type===d.OP.OP_PORT_TYPE_FUNCTION&&this.links.length==0)e=null;if(e&&Object.keys(e).length==1&&e.name)e=null;s(e);return e};b.prototype.shouldLink=function(){return true};b.prototype.removeLinks=function(){let e=0;while(this.links.length>0){e++;if(e>5e3){this._log.warn("could not delete links... / infinite loop");this.links.length=0;break}this.links[0].remove()}};b.prototype.removeLink=function(e){for(const t in this.links)if(this.links[t]==e)this.links.splice(t,1);if(this.direction==d.PORT.PORT_DIR_IN){if(this.type==d.OP.OP_PORT_TYPE_VALUE)this.setValue(this._valueBeforeLink||0);else this.setValue(this._valueBeforeLink||null)}if(CABLES.UI&&this._op.checkLinkTimeWarnings)this._op.checkLinkTimeWarnings();try{if(this.onLinkChanged)this.onLinkChanged();this.emitEvent("onLinkChanged");this.emitEvent("onLinkRemoved");this._op.emitEvent("onLinkChanged")}catch(e){this._log.error(e)}};b.prototype.getName=function(){return this.name};b.prototype.getTitle=function(){if(this.uiAttribs.title)return this.uiAttribs.title;return this.name};b.prototype.addLink=function(e){this._valueBeforeLink=this.value;this.links.push(e);if(CABLES.UI&&this._op.checkLinkTimeWarnings)this._op.checkLinkTimeWarnings();try{if(this.onLinkChanged)this.onLinkChanged();this.emitEvent("onLinkChanged");this._op.emitEvent("onLinkChanged")}catch(e){this._log.error(e)}};b.prototype.getLinkTo=function(e){for(const t in this.links)if(this.links[t].portIn==e||this.links[t].portOut==e)return this.links[t]};b.prototype.removeLinkTo=function(e){for(const t in this.links){if(this.links[t].portIn==e||this.links[t].portOut==e){this.links[t].remove();if(CABLES.UI&&this._op.checkLinkTimeWarnings)this._op.checkLinkTimeWarnings();if(this.onLinkChanged)this.onLinkChanged();this.emitEvent("onLinkChanged");this.emitEvent("onLinkRemoved");return}}};b.prototype.isLinkedTo=function(e){for(const t in this.links)if(this.links[t].portIn==e||this.links[t].portOut==e)return true;return false};b.prototype._activity=function(){this.activityCounter++};b.prototype.trigger=function(){const t=this.links.length;this._activity();if(t===0)return;if(!this._op.enabled)return;let n=null;try{for(let e=0;e<t;++e){if(this.links[e].portIn){n=this.links[e].portIn;n.op.patch.pushTriggerStack(n);n._onTriggered();n.op.patch.popTriggerStack()}if(this.links[e])this.links[e].activity()}}catch(e){n.op.enabled=false;if(this._op.patch.isEditorMode()){if(n.op.onError)n.op.onError(e)}this._log.error("exception in port: ",n.name,n.op.name,n.op);this._log.error(e)}};b.prototype.call=function(){this._log.warn("call deprecated - use trigger() ");this.trigger()};b.prototype.execute=function(){this._log.warn("### execute port: "+this.getName(),this.goals.length)};b.prototype.setVariableName=function(e){this._useVariableName=e;this._op.patch.on("variableRename",(e,t)=>{if(e!=this._useVariableName)return;this._useVariableName=t})};b.prototype.getVariableName=function(){return this._useVariableName};b.prototype.setVariable=function(e){this.setAnimated(false);const t={useVariable:false};if(this._variableIn&&this._varChangeListenerId){this._variableIn.off(this._varChangeListenerId);this._variableIn=null}if(e){this._variableIn=this._op.patch.getVar(e);if(!this._variableIn){this._log.warn("PORT VAR NOT FOUND!!!",e)}else{if(this.type==d.OP.OP_PORT_TYPE_OBJECT){this._varChangeListenerId=this._variableIn.on("change",()=>{this.set(null);this.set(this._variableIn.getValue())})}else{this._varChangeListenerId=this._variableIn.on("change",this.set.bind(this))}this.set(this._variableIn.getValue())}this._useVariableName=e;t.useVariable=true;t.variableName=this._useVariableName}else{t.variableName=this._useVariableName=null;t.useVariable=false}this.setUiAttribs(t);this._op.patch.emitEvent("portSetVariable",this._op,this,e)};b.prototype._handleNoTriggerOpAnimUpdates=function(e){let t=false;for(let e=0;e<this._op.portsIn.length;e++){if(this._op.portsIn.type==d.OP.OP_PORT_TYPE_FUNCTION){t=true;break}}if(!t){if(e)this._notriggerAnimUpdate=this._op.patch.on("onRenderFrame",()=>{this.updateAnim()});else this._op.patch.removeEventListener(this._notriggerAnimUpdate)}};b.prototype.setAnimated=function(e){if(this._animated!=e){this._animated=e;this._op._hasAnimPort=true;if(this._animated&&!this.anim){this.anim=new E({name:"port "+this.name});this.anim.addEventListener("onChange",()=>{this._op.patch.emitEvent("portAnimUpdated",this._op,this,this.anim)})}this._onAnimToggle()}this._handleNoTriggerOpAnimUpdates(e);if(!e){this.anim=null}this.setUiAttribs({isAnimated:this._animated})};b.prototype.toggleAnim=function(){this._animated=!this._animated;if(this._animated&&!this.anim){this.anim=new E({name:"port "+this.name});this.anim.addEventListener("onChange",()=>{this._op.patch.emitEvent("portAnimUpdated",this._op,this,this.anim)})}this.setAnimated(this._animated);this._onAnimToggle();this.setUiAttribs({isAnimated:this._animated})};b.prototype.getType=function(){return this.type};b.prototype.isLinked=function(){return this.links.length>0||this._animated||this._useVariableName!=null};b.prototype.isBoundToVar=function(){const e=this._useVariableName!=null;this.uiAttribs.boundToVar=e;return e};b.prototype.isAnimated=function(){return this._animated};b.prototype.isHidden=function(){return this.uiAttribs.hidePort};b.prototype._onTriggered=function(e){this._activity();this._op.updateAnims();if(this._op.enabled&&this.onTriggered)this.onTriggered(e);if(this._op.enabled)this.emitEvent("trigger")};b.prototype._onSetProfiling=function(e){this._op.patch.profiler.add("port",this);this.setValue(e);this._op.patch.profiler.add("port",null)};b.prototype._onTriggeredProfiling=function(){if(this._op.enabled&&this.onTriggered){this._op.patch.profiler.add("port",this);this.onTriggered();this._op.patch.profiler.add("port",null)}};b.prototype.getUiActiveState=function(){return this._uiActiveState};b.prototype.setUiActiveState=function(e){this._uiActiveState=e;if(this.onUiActiveStateChange)this.onUiActiveStateChange()};b.prototype.onValueChange=function(e){this.onChange=e};b.prototype.hidePort=function(){};b.portTypeNumberToString=function(e){if(e==d.OP.OP_PORT_TYPE_VALUE)return"value";if(e==d.OP.OP_PORT_TYPE_FUNCTION)return"function";if(e==d.OP.OP_PORT_TYPE_OBJECT)return"object";if(e==d.OP.OP_PORT_TYPE_ARRAY)return"array";if(e==d.OP.OP_PORT_TYPE_STRING)return"string";if(e==d.OP.OP_PORT_TYPE_DYNAMIC)return"dynamic";return"unknown"};class B{constructor(e,t,n,i,r,s,a,o,l,h){this._log=new u("cg_uniform");this._type=t;this._name=n;this._shader=e;this._value=1e-5;this._oldValue=null;this._port=null;this._structName=l;this._structUniformName=o;this._propertyName=h;this._shader._addUniform(this);this.needsUpdate=true;this.shaderType=null;this.comment=null;if(t=="f"){this.set=this.setValue=this.setValueF.bind(this);this.updateValue=this.updateValueF.bind(this)}else if(t=="f[]"){this.set=this.setValue=this.setValueArrayF.bind(this);this.updateValue=this.updateValueArrayF.bind(this)}else if(t=="2f[]"){this.set=this.setValue=this.setValueArray2F.bind(this);this.updateValue=this.updateValueArray2F.bind(this)}else if(t=="3f[]"){this.set=this.setValue=this.setValueArray3F.bind(this);this.updateValue=this.updateValueArray3F.bind(this)}else if(t=="4f[]"){this.set=this.setValue=this.setValueArray4F.bind(this);this.updateValue=this.updateValueArray4F.bind(this)}else if(t=="i"){this.set=this.setValue=this.setValueI.bind(this);this.updateValue=this.updateValueI.bind(this)}else if(t=="2i"){this.set=this.setValue=this.setValue2I.bind(this);this.updateValue=this.updateValue2I.bind(this)}else if(t=="3i"){this.set=this.setValue=this.setValue3I.bind(this);this.updateValue=this.updateValue3I.bind(this)}else if(t=="4i"){this.set=this.setValue=this.setValue4I.bind(this);this.updateValue=this.updateValue4I.bind(this)}else if(t=="b"){this.set=this.setValue=this.setValueBool.bind(this);this.updateValue=this.updateValueBool.bind(this)}else if(t=="4f"){this.set=this.setValue=this.setValue4F.bind(this);this.updateValue=this.updateValue4F.bind(this)}else if(t=="3f"){this.set=this.setValue=this.setValue3F.bind(this);this.updateValue=this.updateValue3F.bind(this)}else if(t=="2f"){this.set=this.setValue=this.setValue2F.bind(this);this.updateValue=this.updateValue2F.bind(this)}else if(t=="t"){this.set=this.setValue=this.setValueT.bind(this);this.updateValue=this.updateValueT.bind(this)}else if(t=="sampler"){if(this.setValueAny){this.set=this.setValue=this.setValueAny.bind(this);this.updateValue=this.updateValueAny.bind(this)}}else if(t=="tc"){this.set=this.setValue=this.setValueT.bind(this);this.updateValue=this.updateValueT.bind(this)}else if(t=="t[]"){this.set=this.setValue=this.setValueArrayT.bind(this);this.updateValue=this.updateValueArrayT.bind(this)}else if(t=="m4"||t=="m4[]"){this.set=this.setValue=this.setValueM4.bind(this);this.updateValue=this.updateValueM4.bind(this)}else{this._log.error("Unknown uniform type "+t)}if(typeof i=="object"&&i instanceof b){this._port=i;this._value=this._port.get();if(r&&s&&a){if(!(r instanceof b)||!(s instanceof b)||!(a instanceof b)){this._log.error("[cgl_uniform] mixed port/value parameter for vec4 ",this._name)}this._value=[0,0,0,0];this._port2=r;this._port3=s;this._port4=a;this._port.on("change",this.updateFromPort4f.bind(this));this._port2.on("change",this.updateFromPort4f.bind(this));this._port3.on("change",this.updateFromPort4f.bind(this));this._port4.on("change",this.updateFromPort4f.bind(this));this.updateFromPort4f()}else if(r&&s){if(!(r instanceof b)||!(s instanceof b)){this._log.error("[cgl_uniform] mixed port/value parameter for vec4 ",this._name)}this._value=[0,0,0];this._port2=r;this._port3=s;this._port.on("change",this.updateFromPort3f.bind(this));this._port2.on("change",this.updateFromPort3f.bind(this));this._port3.on("change",this.updateFromPort3f.bind(this));this.updateFromPort3f()}else if(r){if(!(r instanceof b)){this._log.error("[cgl_uniform] mixed port/value parameter for vec4 ",this._name)}this._value=[0,0];this._port2=r;this._port.on("change",this.updateFromPort2f.bind(this));this._port2.on("change",this.updateFromPort2f.bind(this));this.updateFromPort2f()}else{this._port.on("change",this.updateFromPort.bind(this))}}else this._value=i;if(this._value==undefined){console.log("value undefined",this);this._value=0}this.setValue(this._value);this.needsUpdate=true}getType(){return this._type}get type(){return this._type}get name(){return this._name}getName(){return this._name}getValue(){return this._value}getShaderType(){return this.shaderType}isStructMember(){return!!this._structName}updateFromPort4f(){this._value[0]=this._port.get();this._value[1]=this._port2.get();this._value[2]=this._port3.get();this._value[3]=this._port4.get();this.setValue(this._value)}updateFromPort3f(){this._value[0]=this._port.get();this._value[1]=this._port2.get();this._value[2]=this._port3.get();this.setValue(this._value)}updateFromPort2f(){this._value[0]=this._port.get();this._value[1]=this._port2.get();this.setValue(this._value)}updateFromPort(){this.setValue(this._port.get())}}const D=B;class y extends D{constructor(e,t,n,i,r,s,a,o,l,h){super(e,t,n,i,r,s,a,o,l,h);this._loc=-1;this._cgl=e._cgl}get name(){return this._name}copy(e){const t=new y(e,this._type,this._name,this._value,this._port2,this._port3,this._port4,this._structUniformName,this._structName,this._propertyName);t.shaderType=this.shaderType;return t}getGlslTypeString(){return y.glslTypeString(this._type)}_isValidLoc(){return this._loc!=-1}resetLoc(){this._loc=-1;this.needsUpdate=true}bindTextures(){}getLoc(){return this._loc}updateFromPort4f(){this._value[0]=this._port.get();this._value[1]=this._port2.get();this._value[2]=this._port3.get();this._value[3]=this._port4.get();this.setValue(this._value)}updateFromPort3f(){this._value[0]=this._port.get();this._value[1]=this._port2.get();this._value[2]=this._port3.get();this.setValue(this._value)}updateFromPort2f(){this._value[0]=this._port.get();this._value[1]=this._port2.get();this.setValue(this._value)}updateFromPort(){this.setValue(this._port.get())}updateValueF(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;this._shader.getCgl().gl.uniform1f(this._loc,this._value);this._cgl.profileData.profileUniformCount++}setValueF(e){if(e!=this._value){this.needsUpdate=true;this._value=e}}updateValueI(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;this._shader.getCgl().gl.uniform1i(this._loc,this._value);this._cgl.profileData.profileUniformCount++}updateValue2I(){if(!this._value)return;if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}this._shader.getCgl().gl.uniform2i(this._loc,this._value[0],this._value[1]);this.needsUpdate=false;this._cgl.profileData.profileUniformCount++}updateValue3I(){if(!this._value)return;if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}this._shader.getCgl().gl.uniform3i(this._loc,this._value[0],this._value[1],this._value[2]);this.needsUpdate=false;this._cgl.profileData.profileUniformCount++}updateValue4I(){if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}this._shader.getCgl().gl.uniform4i(this._loc,this._value[0],this._value[1],this._value[2],this._value[3]);this._cgl.profileData.profileUniformCount++}setValueI(e){if(e!=this._value){this.needsUpdate=true;this._value=e}}setValue2I(e){if(!e)return;if(!this._oldValue){this._oldValue=[e[0]-1,1];this.needsUpdate=true}else if(e[0]!=this._oldValue[0]||e[1]!=this._oldValue[1]){this._oldValue[0]=e[0];this._oldValue[1]=e[1];this.needsUpdate=true}this._value=e}setValue3I(e){if(!e)return;if(!this._oldValue){this._oldValue=[e[0]-1,1,2];this.needsUpdate=true}else if(e[0]!=this._oldValue[0]||e[1]!=this._oldValue[1]||e[2]!=this._oldValue[2]){this._oldValue[0]=e[0];this._oldValue[1]=e[1];this._oldValue[2]=e[2];this.needsUpdate=true}this._value=e}setValue4I(e){this.needsUpdate=true;this._value=e||vec4.create()}updateValueBool(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;this._shader.getCgl().gl.uniform1i(this._loc,this._value?1:0);this._cgl.profileData.profileUniformCount++}setValueBool(e){if(e!=this._value){this.needsUpdate=true;this._value=e}}setValueArray4F(e){this.needsUpdate=true;this._value=e}updateValueArray4F(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;if(!this._value)return;this._shader.getCgl().gl.uniform4fv(this._loc,this._value);this._cgl.profileData.profileUniformCount++}setValueArray3F(e){this.needsUpdate=true;this._value=e}updateValueArray3F(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;if(!this._value)return;this._shader.getCgl().gl.uniform3fv(this._loc,this._value);this._cgl.profileData.profileUniformCount++}setValueArray2F(e){this.needsUpdate=true;this._value=e}updateValueArray2F(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;if(!this._value)return;this._shader.getCgl().gl.uniform2fv(this._loc,this._value);this._cgl.profileData.profileUniformCount++}setValueArrayF(e){this.needsUpdate=true;this._value=e}updateValueArrayF(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;if(!this._value)return;this._shader.getCgl().gl.uniform1fv(this._loc,this._value);this._cgl.profileData.profileUniformCount++}setValueArrayT(e){this.needsUpdate=true;this._value=e}updateValue3F(){if(!this._value)return;if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}this._shader.getCgl().gl.uniform3f(this._loc,this._value[0],this._value[1],this._value[2]);this.needsUpdate=false;this._cgl.profileData.profileUniformCount++}setValue3F(e){if(!e)return;if(!this._oldValue){this._oldValue=[e[0]-1,1,2];this.needsUpdate=true}else if(e[0]!=this._oldValue[0]||e[1]!=this._oldValue[1]||e[2]!=this._oldValue[2]){this._oldValue[0]=e[0];this._oldValue[1]=e[1];this._oldValue[2]=e[2];this.needsUpdate=true}this._value=e}updateValue2F(){if(!this._value)return;if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}this._shader.getCgl().gl.uniform2f(this._loc,this._value[0],this._value[1]);this.needsUpdate=false;this._cgl.profileData.profileUniformCount++}setValue2F(e){if(!e)return;if(!this._oldValue){this._oldValue=[e[0]-1,1];this.needsUpdate=true}else if(e[0]!=this._oldValue[0]||e[1]!=this._oldValue[1]){this._oldValue[0]=e[0];this._oldValue[1]=e[1];this.needsUpdate=true}this._value=e}updateValue4F(){if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}if(!this._value){this._log.warn("no value for uniform",this._name,this);this._value=[0,0,0,0]}this.needsUpdate=false;this._shader.getCgl().gl.uniform4f(this._loc,this._value[0],this._value[1],this._value[2],this._value[3]);this._cgl.profileData.profileUniformCount++}setValue4F(e){if(typeof this.value=="number")this.value=vec4.create();if(!e)return;if(!this._oldValue){this._oldValue=[e[0]-1,1,2,3];this.needsUpdate=true}else if(e[0]!=this._oldValue[0]||e[1]!=this._oldValue[1]||e[2]!=this._oldValue[2]||e[3]!=this._oldValue[3]){this._oldValue[0]=e[0];this._oldValue[1]=e[1];this._oldValue[2]=e[2];this.needsUpdate=true}this._value=e}updateValueM4(){if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}if(!this._value||this._value.length%16!=0)return console.log("this.name",this._name,this._value);this._shader.getCgl().gl.uniformMatrix4fv(this._loc,false,this._value);this._cgl.profileData.profileUniformCount++}setValueM4(e){this.needsUpdate=true;this._value=e||mat4.create()}updateValueArrayT(){if(!this._isValidLoc())this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);else this.needsUpdate=false;if(!this._value)return;this._shader.getCgl().gl.uniform1iv(this._loc,this._value);this._cgl.profileData.profileUniformCount++}updateValueT(){if(!this._isValidLoc()){this._loc=this._shader.getCgl().gl.getUniformLocation(this._shader.getProgram(),this._name);this._cgl.profileData.profileShaderGetUniform++;this._cgl.profileData.profileShaderGetUniformName=this._name}this._cgl.profileData.profileUniformCount++;this._shader.getCgl().gl.uniform1i(this._loc,this._value);this.needsUpdate=false}setValueT(e){this.needsUpdate=true;this._value=e}}y.glslTypeString=e=>{if(e=="f")return"float";if(e=="b")return"bool";if(e=="i")return"int";if(e=="2i")return"ivec2";if(e=="2f")return"vec2";if(e=="3f")return"vec3";if(e=="4f")return"vec4";if(e=="m4")return"mat4";if(e=="t")return"sampler2D";if(e=="tc")return"samplerCube";if(e=="3f[]")return null;if(e=="m4[]")return null;if(e=="f[]")return null;console.warn("[CGL UNIFORM] unknown glsl type string ",e)};const x={SHADERVAR_VERTEX_POSITION:"vPosition",SHADERVAR_VERTEX_NUMBER:"attrVertIndex",SHADERVAR_VERTEX_NORMAL:"attrVertNormal",SHADERVAR_VERTEX_TEXCOORD:"attrTexCoord",SHADERVAR_INSTANCE_MMATRIX:"instMat",SHADERVAR_VERTEX_COLOR:"attrVertColor",SHADERVAR_INSTANCE_INDEX:"instanceIndex",SHADERVAR_UNI_PROJMAT:"projMatrix",SHADERVAR_UNI_VIEWMAT:"viewMatrix",SHADERVAR_UNI_MODELMAT:"modelMatrix",SHADERVAR_UNI_NORMALMAT:"normalMatrix",SHADERVAR_UNI_INVVIEWMAT:"inverseViewMatrix",SHADERVAR_UNI_INVPROJMAT:"invProjMatrix",SHADERVAR_UNI_MATERIALID:"materialId",SHADERVAR_UNI_OBJECTID:"objectId",SHADERVAR_UNI_VIEWPOS:"camPos"};const S={BLEND_NONE:0,BLEND_NORMAL:1,BLEND_ADD:2,BLEND_SUB:3,BLEND_MUL:4};const T=180/Math.PI;const O=Math.PI/180;const I={MATH:{DEG2RAD:O,RAD2DEG:T},SHADER:x,BLEND_MODES:S};const w={};w.lastMesh=null;const L=function(e,t,n){this._cgl=e;let i=n||{};if(CABLES.UTILS.isNumeric(i))i={glPrimitive:n};this._log=new u("cgl_mesh");this._bufVertexAttrib=null;this._bufVerticesIndizes=this._cgl.gl.createBuffer();this._indexType=this._cgl.gl.UNSIGNED_SHORT;this._attributes=[];this._attribLocs={};this._geom=null;this._lastShader=null;this._numInstances=0;this._glPrimitive=i.glPrimitive;this.opId=i.opId||"";this._preWireframeGeom=null;this.addVertexNumbers=false;this._name="unknown";this.feedBackAttributes=[];this.setGeom(t);this._feedBacks=[];this._feedBacksChanged=false;this._transformFeedBackLoc=-1;this._lastAttrUpdate=0;this.memFreed=false;this._cgl.profileData.addHeavyEvent("mesh constructed",this._name);this._queryExt=null;Object.defineProperty(this,"numInstances",{get(){return this._numInstances},set(e){this.setNumInstances(e)}})};L.prototype.freeMem=function(){this.memFreed=true;for(let e=0;e<this._attributes.length;e++){this._attributes[e].floatArray=null}};L.prototype.updateVertices=function(e){this.setAttribute(I.SHADER.SHADERVAR_VERTEX_POSITION,e.vertices,3);this._numVerts=e.vertices.length/3};L.prototype.setAttributePointer=function(t,n,i,r){for(let e=0;e<this._attributes.length;e++){if(this._attributes[e].name==t){if(!this._attributes[e].pointer)this._attributes[e].pointer=[];this._attributes[e].pointer.push({loc:-1,name:n,stride:i,offset:r,instanced:t==I.SHADER.SHADERVAR_INSTANCE_MMATRIX})}}};L.prototype.getAttribute=function(t){for(let e=0;e<this._attributes.length;e++)if(this._attributes[e].name==t)return this._attributes[e]};L.prototype.setAttributeRange=function(e,t,n,i){if(!e)return;if(!n&&!i)return;if(!e.name){this._log.stack("no attrname?!")}this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER,e.buffer);this._cgl.profileData.profileMeshAttributes+=i-n||0;this._cgl.profileData.profileSingleMeshAttribute[this._name]=this._cgl.profileData.profileSingleMeshAttribute[this._name]||0;this._cgl.profileData.profileSingleMeshAttribute[this._name]+=i-n||0;if(e.numItems<t.length/e.itemSize){this._resizeAttr(t,e)}if(i>t.length){if(CABLES.platform.isDevEnv())this._log.log(this._cgl.canvas.id+" "+e.name+" buffersubdata out of bounds ?",t.length,i,n,e);return}if(this._cgl.glVersion==1)this._cgl.gl.bufferSubData(this._cgl.gl.ARRAY_BUFFER,0,t);else this._cgl.gl.bufferSubData(this._cgl.gl.ARRAY_BUFFER,n*4,t,n,i-n)};L.prototype._resizeAttr=function(e,t){if(t.buffer)this._cgl.gl.deleteBuffer(t.buffer);t.buffer=this._cgl.gl.createBuffer();this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER,t.buffer);this._bufferArray(e,t);t.numItems=e.length/t.itemSize};L.prototype._bufferArray=function(e,t){let n=t.floatArray||null;if(!e)return;if(this._cgl.debugOneFrame){console.log("_bufferArray",e.length,t.name)}if(!(e instanceof Float32Array)){if(t&&n&&n.length==e.length){n.set(e)}else{n=new Float32Array(e);if(this._cgl.debugOneFrame){console.log("_bufferArray create new float32array",e.length,t.name)}if(e.length>1e4){this._cgl.profileData.profileNonTypedAttrib++;this._cgl.profileData.profileNonTypedAttribNames="("+this._name+":"+t.name+")"}}}else n=e;t.arrayLength=n.length;t.floatArray=null;this._cgl.gl.bufferData(this._cgl.gl.ARRAY_BUFFER,n,this._cgl.gl.DYNAMIC_DRAW)};L.prototype.addAttribute=L.prototype.updateAttribute=L.prototype.setAttribute=function(e,t,n,i){if(!t){this._log.error("mesh addAttribute - no array given! "+e);throw new Error}let r=null;let s=false;let a=0;const o=t.length/n;this._cgl.profileData.profileMeshAttributes+=o||0;if(typeof i=="function"){r=i}if(typeof i=="object"){if(i.cb)r=i.cb;if(i.instanced)s=i.instanced}if(e==I.SHADER.SHADERVAR_INSTANCE_MMATRIX)s=true;for(a=0;a<this._attributes.length;a++){const u=this._attributes[a];if(u.name==e){if(u.numItems===o){}else{this._resizeAttr(t,u)}this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER,u.buffer);this._bufferArray(t,u);return u}}const l=this._cgl.gl.createBuffer();this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER,l);let h=this._cgl.gl.FLOAT;if(i&&i.type)h=i.type;const u={buffer:l,name:e,cb:r,itemSize:n,numItems:o,startItem:0,instanced:s,type:h};this._bufferArray(t,u);if(e==I.SHADER.SHADERVAR_VERTEX_POSITION)this._bufVertexAttrib=u;this._attributes.push(u);this._attribLocs={};return u};L.prototype.getAttributes=function(){return this._attributes};L.prototype.updateTexCoords=function(e){if(e.texCoords&&e.texCoords.length>0){this.setAttribute(I.SHADER.SHADERVAR_VERTEX_TEXCOORD,e.texCoords,2)}else{const t=new Float32Array(Math.round(e.vertices.length/3*2));this.setAttribute(I.SHADER.SHADERVAR_VERTEX_TEXCOORD,t,2)}};L.prototype.updateNormals=function(e){if(e.vertexNormals&&e.vertexNormals.length>0){this.setAttribute(I.SHADER.SHADERVAR_VERTEX_NORMAL,e.vertexNormals,3)}else{const t=new Float32Array(Math.round(e.vertices.length));this.setAttribute(I.SHADER.SHADERVAR_VERTEX_NORMAL,t,3)}};L.prototype._setVertexNumbers=function(e){if(!this._verticesNumbers||this._verticesNumbers.length!=this._numVerts||e){if(e)this._verticesNumbers=e;else{this._verticesNumbers=new Float32Array(this._numVerts);for(let e=0;e<this._numVerts;e++)this._verticesNumbers[e]=e}this.setAttribute(I.SHADER.SHADERVAR_VERTEX_NUMBER,this._verticesNumbers,1,(e,t,n)=>{if(!n.uniformNumVertices)n.uniformNumVertices=new y(n,"f","numVertices",this._numVerts);n.uniformNumVertices.setValue(this._numVerts)})}};L.prototype.setVertexIndices=function(t){if(!this._bufVerticesIndizes){this._log.warn("no bufVerticesIndizes: "+this._name);return}if(t.length>0){if(t instanceof Float32Array)this._log.warn("vertIndices float32Array: "+this._name);for(let e=0;e<t.length;e++){if(t[e]>=this._numVerts){this._log.warn("invalid index in "+this._name,e,t[e]);return}}this._cgl.gl.bindBuffer(this._cgl.gl.ELEMENT_ARRAY_BUFFER,this._bufVerticesIndizes);if(t.length>65535){this.vertIndicesTyped=new Uint32Array(t);this._indexType=this._cgl.gl.UNSIGNED_INT}else if(t instanceof Uint32Array){this.vertIndicesTyped=t;this._indexType=this._cgl.gl.UNSIGNED_INT}else if(!(t instanceof Uint16Array)){this.vertIndicesTyped=new Uint16Array(t);this._indexType=this._cgl.gl.UNSIGNED_SHORT}else this.vertIndicesTyped=t;this._cgl.gl.bufferData(this._cgl.gl.ELEMENT_ARRAY_BUFFER,this.vertIndicesTyped,this._cgl.gl.DYNAMIC_DRAW);this._bufVerticesIndizes.itemSize=1;this._bufVerticesIndizes.numItems=t.length}else this._bufVerticesIndizes.numItems=0};L.prototype.setGeom=function(e,t){this._geom=e;if(e.glPrimitive!=null)this._glPrimitive=e.glPrimitive;if(this._geom&&this._geom.name)this._name="mesh "+this._geom.name;w.lastMesh=null;this._cgl.profileData.profileMeshSetGeom++;this._disposeAttributes();this.updateVertices(this._geom);this.setVertexIndices(this._geom.verticesIndices);if(this.addVertexNumbers)this._setVertexNumbers();const n=this._geom.getAttributes();const i={texCoords:I.SHADER.SHADERVAR_VERTEX_TEXCOORD,vertexNormals:I.SHADER.SHADERVAR_VERTEX_NORMAL,vertexColors:I.SHADER.SHADERVAR_VERTEX_COLOR,tangents:"attrTangent",biTangents:"attrBiTangent"};for(const r in n)if(n[r].data&&n[r].data.length)this.setAttribute(i[r]||r,n[r].data,n[r].itemSize);if(t){this._geom=null}};L.prototype._preBind=function(t){for(let e=0;e<this._attributes.length;e++)if(this._attributes[e].cb)this._attributes[e].cb(this._attributes[e],this._geom,t)};L.prototype._checkAttrLengths=function(){if(this.memFreed)return;for(let e=0;e<this._attributes.length;e++){if(this._attributes[e].arrayLength/this._attributes[e].itemSize<this._attributes[0].arrayLength/this._attributes[0].itemSize){let e="unknown";if(this._geom)e=this._geom.name}}};L.prototype._bind=function(t){if(!t.isValid())return;let n=[];if(this._attribLocs[t.id])n=this._attribLocs[t.id];else this._attribLocs[t.id]=n;this._lastShader=t;if(t.lastCompile>this._lastAttrUpdate||n.length!=this._attributes.length){this._lastAttrUpdate=t.lastCompile;for(let e=0;e<this._attributes.length;e++)n[e]=-1}for(let e=0;e<this._attributes.length;e++){const i=this._attributes[e];if(n[e]==-1){if(i._attrLocationLastShaderTime!=t.lastCompile){i._attrLocationLastShaderTime=t.lastCompile;n[e]=this._cgl.glGetAttribLocation(t.getProgram(),i.name);this._cgl.profileData.profileAttrLoc++}}if(n[e]!=-1){this._cgl.gl.enableVertexAttribArray(n[e]);this._cgl.gl.bindBuffer(this._cgl.gl.ARRAY_BUFFER,i.buffer);if(i.instanced){if(i.itemSize<=4){if(!i.itemSize||i.itemSize==0)this._log.warn("instanced attrib itemsize error",this._geom.name,i);this._cgl.gl.vertexAttribPointer(n[e],i.itemSize,i.type,false,i.itemSize*4,0);this._cgl.gl.vertexAttribDivisor(n[e],1)}else if(i.itemSize==16){const r=16*4;this._cgl.gl.vertexAttribPointer(n[e],4,i.type,false,r,0);this._cgl.gl.enableVertexAttribArray(n[e]+1);this._cgl.gl.vertexAttribPointer(n[e]+1,4,i.type,false,r,4*4*1);this._cgl.gl.enableVertexAttribArray(n[e]+2);this._cgl.gl.vertexAttribPointer(n[e]+2,4,i.type,false,r,4*4*2);this._cgl.gl.enableVertexAttribArray(n[e]+3);this._cgl.gl.vertexAttribPointer(n[e]+3,4,i.type,false,r,4*4*3);this._cgl.gl.vertexAttribDivisor(n[e],1);this._cgl.gl.vertexAttribDivisor(n[e]+1,1);this._cgl.gl.vertexAttribDivisor(n[e]+2,1);this._cgl.gl.vertexAttribDivisor(n[e]+3,1)}else{this._log.warn("unknown instance attrib size",i.name)}}else{if(!i.itemSize||i.itemSize==0)this._log.warn("attrib itemsize error",this._name,i);this._cgl.gl.vertexAttribPointer(n[e],i.itemSize,i.type,false,i.itemSize*4,0);if(i.pointer){for(let e=0;e<i.pointer.length;e++){const s=i.pointer[e];if(s.loc==-1)s.loc=this._cgl.glGetAttribLocation(t.getProgram(),s.name);this._cgl.profileData.profileAttrLoc++;this._cgl.gl.enableVertexAttribArray(s.loc);this._cgl.gl.vertexAttribPointer(s.loc,i.itemSize,i.type,false,s.stride,s.offset)}}if(this.bindFeedback)this.bindFeedback(i)}}}if(this._bufVerticesIndizes&&this._bufVerticesIndizes.numItems!==0)this._cgl.gl.bindBuffer(this._cgl.gl.ELEMENT_ARRAY_BUFFER,this._bufVerticesIndizes)};L.prototype.unBind=function(){const e=this._lastShader;this._lastShader=null;if(!e)return;let t=[];if(this._attribLocs[e.id])t=this._attribLocs[e.id];else this._attribLocs[e.id]=t;w.lastMesh=null;for(let e=0;e<this._attributes.length;e++){if(this._attributes[e].instanced){if(this._attributes[e].itemSize<=4){if(t[e]!=-1)this._cgl.gl.vertexAttribDivisor(t[e],0);if(t[e]>=0)this._cgl.gl.disableVertexAttribArray(t[e])}else{this._cgl.gl.vertexAttribDivisor(t[e],0);this._cgl.gl.vertexAttribDivisor(t[e]+1,0);this._cgl.gl.vertexAttribDivisor(t[e]+2,0);this._cgl.gl.vertexAttribDivisor(t[e]+3,0);this._cgl.gl.disableVertexAttribArray(t[e]+1);this._cgl.gl.disableVertexAttribArray(t[e]+2);this._cgl.gl.disableVertexAttribArray(t[e]+3)}}if(t[e]!=-1)this._cgl.gl.disableVertexAttribArray(t[e])}};L.prototype.meshChanged=function(){return this._cgl.lastMesh&&this._cgl.lastMesh!=this};L.prototype.printDebug=function(e){console.log("--attributes");for(let e=0;e<this._attributes.length;e++){console.log("attribute "+e+" "+this._attributes[e].name)}};L.prototype.setNumVertices=function(e){this._bufVertexAttrib.numItems=e};L.prototype.getNumVertices=function(){return this._bufVertexAttrib.numItems};L.prototype.render=function(n){if(!n||!n.isValid()||this._cgl.aborted)return;this._checkAttrLengths();if(this._geom){if(this._preWireframeGeom&&!n.wireframe&&!this._geom.isIndexed()){this.setGeom(this._preWireframeGeom);this._preWireframeGeom=null}if(n.wireframe){let e=false;if(this._geom.isIndexed()){if(!this._preWireframeGeom){this._preWireframeGeom=this._geom;this._geom=this._geom.copy()}this._geom.unIndex();e=true}if(!this._geom.getAttribute("attrBarycentric")){if(!this._preWireframeGeom){this._preWireframeGeom=this._geom;this._geom=this._geom.copy()}e=true;this._geom.calcBarycentric()}if(e)this.setGeom(this._geom)}}let e=false;if(w.lastMesh!=this){if(w.lastMesh)w.lastMesh.unBind();e=true}if(e)this._preBind(n);if(!n.bind())return;this._bind(n);if(this.addVertexNumbers)this._setVertexNumbers();w.lastMesh=this;let t=this._cgl.gl.TRIANGLES;if(this._glPrimitive!==undefined)t=this._glPrimitive;if(n.glPrimitive!==null)t=n.glPrimitive;let i=1;let r=this._cgl.profileData.doProfileGlQuery;let s=false;if(r){let e=this._name+" - "+n.getName()+" #"+n.id;if(this._numInstances)e+=" instanced "+this._numInstances+"x";let t=this._cgl.profileData.glQueryData[e];if(!t)t={id:e,num:0};if(n.opId)t.shaderOp=n.opId;if(this.opId)t.meshOp=this.opId;this._cgl.profileData.glQueryData[e]=t;if(!this._queryExt&&this._queryExt!==false)this._queryExt=this._cgl.enableExtension("EXT_disjoint_timer_query_webgl2")||false;if(this._queryExt){if(t._drawQuery){const a=this._cgl.gl.getQueryParameter(t._drawQuery,this._cgl.gl.QUERY_RESULT_AVAILABLE);if(a){const o=this._cgl.gl.getQueryParameter(t._drawQuery,this._cgl.gl.QUERY_RESULT);const l=o/1e6;t._times=t._times||0;t._times+=l;t._numcount++;t.when=performance.now();t._drawQuery=null;t.queryStarted=false}}if(!t.queryStarted){t._drawQuery=this._cgl.gl.createQuery();this._cgl.gl.beginQuery(this._queryExt.TIME_ELAPSED_EXT,t._drawQuery);s=t.queryStarted=true}}}if(this.hasFeedbacks&&this.hasFeedbacks())this.drawFeedbacks(n,t);else if(!this._bufVerticesIndizes||this._bufVerticesIndizes.numItems===0){if(t==this._cgl.gl.TRIANGLES)i=3;if(this._numInstances===0)this._cgl.gl.drawArrays(t,this._bufVertexAttrib.startItem,this._bufVertexAttrib.numItems-this._bufVertexAttrib.startItem);else this._cgl.gl.drawArraysInstanced(t,this._bufVertexAttrib.startItem,this._bufVertexAttrib.numItems,this._numInstances)}else{if(t==this._cgl.gl.TRIANGLES)i=3;if(this._numInstances===0){this._cgl.gl.drawElements(t,this._bufVerticesIndizes.numItems,this._indexType,0)}else{this._cgl.gl.drawElementsInstanced(t,this._bufVerticesIndizes.numItems,this._indexType,0,this._numInstances)}}if(this._cgl.debugOneFrame&&this._cgl.gl.getError()!=this._cgl.gl.NO_ERROR){this._log.error("mesh draw gl error");this._log.error("mesh",this);this._log.error("shader",n);const h=[];for(let e=0;e<this._cgl.gl.getProgramParameter(n.getProgram(),this._cgl.gl.ACTIVE_ATTRIBUTES);e++){const u=this._cgl.gl.getActiveAttrib(n.getProgram(),e).name;this._log.error("attrib ",u)}}this._cgl.profileData.profileMeshNumElements+=this._bufVertexAttrib.numItems/i*(this._numInstances||1);this._cgl.profileData.profileMeshDraw++;if(r&&s){this._cgl.gl.endQuery(this._queryExt.TIME_ELAPSED_EXT)}this._cgl.printError("mesh render "+this._name);this.unBind()};L.prototype.setNumInstances=function(t){t=Math.max(0,t);if(this._numInstances!=t){this._numInstances=t;const n=new Float32Array(t);for(let e=0;e<t;e++)n[e]=e;this.setAttribute(I.SHADER.SHADERVAR_INSTANCE_INDEX,n,1,{instanced:true})}};L.prototype._disposeAttributes=function(){if(!this._attributes)return;for(let e=0;e<this._attributes.length;e++){if(this._attributes[e].buffer){this._cgl.gl.deleteBuffer(this._attributes[e].buffer);this._attributes[e].buffer=null}}this._attributes.length=0};L.prototype.dispose=function(){if(this._bufVertexAttrib&&this._bufVertexAttrib.buffer)this._cgl.gl.deleteBuffer(this._bufVertexAttrib.buffer);if(this._bufVerticesIndizes)this._cgl.gl.deleteBuffer(this._bufVerticesIndizes);this._bufVerticesIndizes=null;this._disposeAttributes()};const N={};N.getSimpleRect=function(e,t,n=1){const i=new f(t);i.vertices=[1*n,1*n,0,-1*n,1*n,0,1*n,-1*n,0,-1*n,-1*n,0];i.texCoords=[1,1,0,1,1,0,0,0];i.verticesIndices=[0,1,2,2,1,3];i.vertexNormals=[0,0,0,0,0,0,0,0,0,0,0,0];return e.createMesh(i)};N.getSimpleCube=function(e,t){const n=new f(t);n.vertices=[-1,-1,1,1,-1,1,1,1,1,-1,1,1,-1,-1,-1,1,-1,-1,1,1,-1,-1,1,-1,-1,1,-1,1,1,-1,1,1,1,-1,1,1,-1,-1,-1,1,-1,-1,1,-1,1,-1,-1,1,1,-1,-1,1,-1,1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,1,-1,1,1,-1,1,-1];n.setTexCoords([0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,1,0,0,0,1,1,1,1,0,1,0,0,0,0,1,1,1,1,1,1,0,0,0,0,1,0,1,1,1,1,0,0,0]);n.verticesIndices=[0,1,2,0,2,3,4,5,6,4,6,7,8,9,10,8,10,11,12,13,14,12,14,15,16,17,18,16,18,19,20,21,22,20,22,23];n.vertexNormals=new Float32Array([0,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0]);n.tangents=new Float32Array([0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1]);n.biTangents=new Float32Array([-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1]);return new L(e,n)};class R{constructor(e,t,n){this.cgl=e;this._options=n;this.fb=null;let i=n.shader;this._useDefaultShader=true;if(n.shader)this._useDefaultShader=false;n.numRenderBuffers=n.numRenderBuffers||1;if(!i){i="".endl()+"IN vec2 texCoord;";for(let e=0;e<n.numRenderBuffers;e++){i=i.endl()+"UNI sampler2D tex"+e+";".endl()}i=i.endl()+"void main()".endl()+"{";if(n.numRenderBuffers==1){i=i.endl()+"    outColor= texture(tex0,texCoord);".endl()}else for(let e=0;e<n.numRenderBuffers;e++){i=i.endl()+"outColor"+e+" = texture(tex"+e+",texCoord);".endl()}i=i.endl()+"}"}const r=n.vertexShader||"".endl()+"IN vec3 vPosition;".endl()+"IN vec2 attrTexCoord;".endl()+"OUT vec2 texCoord;".endl()+"void main()".endl()+"{".endl()+"   texCoord=attrTexCoord;".endl()+"   gl_Position = vec4(vPosition,  1.0);".endl()+"}";this.bgShader=new CGL.Shader(e,"corelib copytexture "+t);this.bgShader.setSource(r,i);if(!n.vertexShader)this.bgShader.ignoreMissingUniforms=true;new CGL.Uniform(this.bgShader,"t","tex",0);new CGL.Uniform(this.bgShader,"t","tex1",1);new CGL.Uniform(this.bgShader,"t","tex2",2);new CGL.Uniform(this.bgShader,"t","tex3",3);this.mesh=N.getSimpleRect(this.cgl,"texEffectRect")}setSize(e,t){this._options.width=e;this._options.height=t}copy(e,t,n,i,r){const s=this.cgl;if(!e)e=CGL.Texture.getEmptyTexture(this.cgl);let a=this._options.width||e.width,o=this._options.height||e.height;if(this.fb){if(a<=0)a=8;if(o<=0)o=8;if(this.fb.getWidth()!=a||this.fb.getHeight()!=o)this.fb.setSize(a,o)}else{let e=CGL.Texture.FILTER_LINEAR;let t=CGL.Texture.WRAP_CLAMP_TO_EDGE;if(this._options.isFloatingPointTexture)e=CGL.Texture.FILTER_NEAREST;if(this._options.hasOwnProperty("filter"))e=this._options.filter;if(this._options.hasOwnProperty("wrap"))t=this._options.wrap;const l={isFloatingPointTexture:this._options.isFloatingPointTexture,pixelFormat:this._options.pixelFormat,numRenderBuffers:this._options.numRenderBuffers||1,filter:e,wrap:t};if(s.glVersion==1)this.fb=new CGL.Framebuffer(s,a,o,l);else this.fb=new CGL.Framebuffer2(s,a,o,l)}s.tempData.renderOffscreen=true;this.fb.renderStart(s);s.setTexture(0,e.tex);if(t)s.setTexture(1,t.tex);if(n)s.setTexture(2,n.tex);if(i)s.setTexture(3,i.tex);if(r)s.setTexture(4,r.tex);s.pushShader(this.bgShader);this.mesh.render(this.bgShader);s.popShader();this.fb.renderEnd();s.tempData.renderOffscreen=false;return this.fb.getTextureColor()}dispose(){if(this.fb)this.fb.dispose();if(this.bgShader)this.bgShader.dispose();if(this.mesh)this.mesh.dispose()}}CGL.CopyTexture=R;((this.CGL=this.CGL||{}).COREMODULES=this.CGL.COREMODULES||{}).Copytexture=e.Copytexture})();(()=>{"use strict";var e={};class t{constructor(e,t,n){this._cgl=e;this._name=t;this._origShaders={};this._uniforms=[];this._structUniforms=[];this._definesToggled={};this._defines={};this._mods=[];this._textures=[];this._boundShader=null;this._changedDefines=true;this._changedUniforms=true;this._modulesChanged=false;this.needsTexturePush=false;this._lastShader=null;this._attributes=[];if(n&&n.opId)this.opId=n.opId;if(this._cgl.glVersion==1){this._cgl.enableExtension("OES_texture_float");this._cgl.enableExtension("OES_texture_float_linear");this._cgl.enableExtension("OES_texture_half_float");this._cgl.enableExtension("OES_texture_half_float_linear")}}bind(e,t){const n=e||this._cgl.getShader();if(!n)return;this._boundShader=this._origShaders[n.id];let i=false;if(this._boundShader&&this._lastShader!=this._boundShader.shader){if(!this._boundShader.shader.hasModule(this._mods[0].id))i=true}if(i||!this._boundShader||n.lastCompile!=this._boundShader.lastCompile||this._modulesChanged||n._needsRecompile){if(this._boundShader)this._boundShader.shader.dispose();if(n._needsRecompile)n.compile();this.needsTexturePush=true;this._boundShader=this._origShaders[n.id]={lastCompile:n.lastCompile,orig:n,shader:n.copy()};this._addModulesToShader(this._boundShader.shader);this._updateDefinesShader(this._boundShader.shader);this._updateUniformsShader(this._boundShader.shader)}this._boundShader.wireframe=n.wireframe;if(this._changedDefines)this._updateDefines();if(this._changedUniforms)this._updateUniforms();if(t!==false)this._cgl.pushShader(this._boundShader.shader);this._boundShader.shader.copyUniformValues(this._boundShader.orig);if(this.needsTexturePush){for(let e=0;e<this._textures.length;e++){const r=this._textures[e][0];const s=this._textures[e][1];const a=this._textures[e][2];if(this._getUniform(r)){const o=this.getPrefixedName(r);const l=this._boundShader.shader.getUniform(o);if(l)this._boundShader.shader.pushTexture(l,s,a)}}this.needsTexturePush=false;this._textures.length=0}this._modulesChanged=false;this._boundShader.shader.fromMod=this;if(this.onBind)this.onBind(this._boundShader.shader);return this._boundShader.shader}unbind(e){if(this._boundShader){if(e!==false)this._cgl.popShader()}this._boundShader=null}_addModulesToShader(t){let n;if(this._mods.length>1)n=this._mods[0];for(let e=0;e<this._mods.length;e++)t.addModule(this._mods[e],n)}_removeModulesFromShader(e){for(const t in this._origShaders)this._origShaders[t].shader.removeModule(e)}addModule(e){this._mods.push(e);this._modulesChanged=true}removeModule(t){const n=[];let i=false;for(let e=0;e<this._mods.length;e++){if(this._mods[e].title==t){i=true;this._removeModulesFromShader(this._mods[e]);n.push(e)}}for(let e=n.length-1;e>=0;e-=1)this._mods.splice(n[e],1);this._modulesChanged=true}_updateUniformsShader(i){for(let e=0;e<this._uniforms.length;e++){const t=this._uniforms[e];const n=this.getPrefixedName(t.name);if(!i.hasUniform(n)&&!t.structName){let e=null;if(t.shaderType==="both"){e=i.addUniformBoth(t.type,n,t.v1,t.v2,t.v3,t.v4);e.comment="mod: "+this._name}else if(t.shaderType==="frag"){e=i.addUniformFrag(t.type,n,t.v1,t.v2,t.v3,t.v4);e.comment="mod: "+this._name}else if(t.shaderType==="vert"){e=i.addUniformVert(t.type,n,t.v1,t.v2,t.v3,t.v4);e.comment="mod: "+this._name}}}for(let n=0;n<this._structUniforms.length;n+=1){const r=this._structUniforms[n];let e=r.uniformName;let t=r.structName;const s=r.members;e=this.getPrefixedName(r.uniformName);t=this.getPrefixedName(r.structName);if(r.shaderType==="frag"){i.addUniformStructFrag(t,e,s)}if(r.shaderType==="vert"){i.addUniformStructVert(t,e,s)}if(r.shaderType==="both"){i.addUniformStructBoth(t,e,s)}}}_updateUniforms(){for(const e in this._origShaders)this._updateUniformsShader(this._origShaders[e].shader);this._changedUniforms=false}_setUniformValue(e,t,n){const i=e.getUniform(t);if(i)i.setValue(n)}setUniformValue(e,t){const n=this._getUniform(e);if(!n)return;const i=this.getPrefixedName(e);for(const r in this._origShaders){this._setUniformValue(this._origShaders[r].shader,i,t)}}hasUniform(e){return this._getUniform(e)}_getUniform(t){for(let e=0;e<this._uniforms.length;e++){if(this._uniforms[e].name==t)return this._uniforms[e];if(this._uniforms[e].structName){if(this._uniforms[e].propertyName==t)return this._uniforms[e]}}return false}_getStructUniform(t){for(let e=0;e<this._structUniforms.length;e+=1)if(this._structUniforms[e].uniformName===t)return this._structUniforms[e];return null}_isStructUniform(t){for(let e=0;e<this._uniforms.length;e++){if(this._uniforms[e].name==t)return false;if(this._uniforms[e].structName){if(this._uniforms[e].propertyName==t)return true}}return false}addUniform(t,n,i,r,s,a,o,l,h,u){if(!this._getUniform(n)){let e="both";if(u)e=u;this._uniforms.push({type:t,name:n,v1:i,v2:r,v3:s,v4:a,structUniformName:o,structName:l,propertyName:h,shaderType:e});this._changedUniforms=true}}addUniformFrag(e,t,n,i,r,s){this.addUniform(e,t,n,i,r,s,null,null,null,"frag");this._changedUniforms=true}addUniformVert(e,t,n,i,r,s){this.addUniform(e,t,n,i,r,s,null,null,null,"vert");this._changedUniforms=true}addUniformBoth(e,t,n,i,r,s){this.addUniform(e,t,n,i,r,s,null,null,null,"both");this._changedUniforms=true}addUniformStruct(t,n,i,r){for(let e=0;e<i.length;e+=1){const s=i[e];if((s.type==="2i"||s.type==="i"||s.type==="3i")&&r==="both")console.error("Adding an integer struct member to both shaders can potentially error. Please use different structs for each shader. Error occured in struct:",t," with member:",s.name," of type:",s.type,".");if(!this._getUniform(n+"."+s.name)){this.addUniform(s.type,n+"."+s.name,s.v1,s.v2,s.v3,s.v4,n,t,s.name,r)}}if(!this._getStructUniform(n)){this._structUniforms.push({structName:t,uniformName:n,members:i,shaderType:r})}}addUniformStructVert(e,t,n){this.addUniformStruct(e,t,n,"vert")}addUniformStructFrag(e,t,n){this.addUniformStruct(e,t,n,"frag")}addUniformStructBoth(e,t,n){this.addUniformStruct(e,t,n,"both")}addAttribute(t){for(let e=0;e<this._attributes.length;e++){if(this._attributes[e].name==t.name&&this._attributes[e].nameFrag==t.nameFrag)return}this._attributes.push(t)}pushTexture(e,t,n){if(!t)throw new Error("no texture given to texturestack");this._textures.push([e,t,n]);this.needsTexturePush=true}_removeUniformFromShader(e,t){if(t.hasUniform(e))t.removeUniform(e)}removeUniform(t){if(this._getUniform(t)){for(let e=this._uniforms.length-1;e>=0;e-=1){const n=t;if(this._uniforms[e].name==t&&!this._uniforms[e].structName){for(const i in this._origShaders){this._removeUniformFromShader(this.getPrefixedName(n),this._origShaders[i].shader)}this._uniforms.splice(e,1)}}this._changedUniforms=true}}removeUniformStruct(t){if(this._getStructUniform(t)){for(let e=this._structUniforms.length-1;e>=0;e-=1){const n=this._structUniforms[e];if(n.uniformName===t){for(const i in this._origShaders){for(let e=0;e<n.members.length;e+=1){const r=n.members[e];this._removeUniformFromShader(this.getPrefixedName(r.name),this._origShaders[i].shader)}}this._structUniforms.splice(e,1)}}this._changedUniforms=true}}getPrefixedName(e){const t=this._mods[0].group;if(t===undefined){return}if(e.startsWith("MOD_")){e=e.substr("MOD_".length);e="mod"+t+"_"+e}return e}_updateDefinesShader(e){for(const t in this._defines){const n=this.getPrefixedName(t);if(this._defines[t]!==null&&this._defines[t]!==undefined)e.define(n,this._defines[t]);else e.removeDefine(n)}for(const t in this._definesToggled){const n=this.getPrefixedName(t);e.toggleDefine(n,this._definesToggled[t])}}_updateDefines(){for(const e in this._origShaders)this._updateDefinesShader(this._origShaders[e].shader);this._changedDefines=false}define(e,t){if(t===undefined)t=true;this._defines[e]=t;this._changedDefines=true}removeDefine(e){this._defines[e]=null;this._changedDefines=true}hasDefine(e){if(this._defines[e]!==null&&this._defines[e]!==undefined)return true;return false}toggleDefine(e,t){this._changedDefines=true;this._definesToggled[e]=t}currentShader(){if(!this._boundShader)return null;return this._boundShader.shader}dispose(){}}CGL.ShaderModifier=t;((this.CGL=this.CGL||{}).COREMODULES=this.CGL.COREMODULES||{}).Shadermodifier=e.Shadermodifier})();(()=>{"use strict";var e={};const t=class{constructor(){this.patch=null;this.fsElement=null;this.callbacks={}}add(e,t,n){this.patch=e;this.callbacks[t]=n;this.show()}remove(e){delete this.callbacks[e];if(Object.keys(this.callbacks).length==0){if(this.fsElement)this.fsElement.remove();this.fsElement=null}}show(){if(!this.fsElement){this.fsElement=document.createElement("div");const e=this.patch.cgl.canvas.parentElement;if(e)e.appendChild(this.fsElement);this.fsElement.addEventListener("pointerdown",e=>{for(const t in this.callbacks)this.callbacks[t]()})}this.fsElement.style.padding="10px";this.fsElement.style.position="absolute";this.fsElement.style.right="20px";this.fsElement.style.bottom="20px";this.fsElement.style.width="24px";this.fsElement.style.height="24px";this.fsElement.style.cursor="pointer";this.fsElement.style["border-radius"]="40px";this.fsElement.style.background="#444";this.fsElement.style["z-index"]="9999";this.fsElement.style.display="block";this.fsElement.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="feather feather-volume-2"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon><path d="M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07"></path></svg>'}};CABLES.interActionNeededButton=CABLES.interActionNeededButton||new t;((this.CABLES=this.CABLES||{}).COREMODULES=this.CABLES.COREMODULES||{}).Interactionneededbutton=e.Cables})();