{"version":3,"file":"GlslCanvas.min.js","sources":["../node_modules/global/window.js","../node_modules/is-function/index.js","../node_modules/parse-headers/parse-headers.js","../node_modules/xtend/immutable.js","../node_modules/xhr/index.js","../src/gl/gl.js","../src/tools/common.js","../src/tools/mixin.js","../src/gl/Texture.js","../src/GlslCanvas.js"],"sourcesContent":["var win;\n\nif (typeof window !== \"undefined\") {\n win = window;\n} else if (typeof global !== \"undefined\") {\n win = global;\n} else if (typeof self !== \"undefined\"){\n win = self;\n} else {\n win = {};\n}\n\nmodule.exports = win;\n","module.exports = isFunction\n\nvar toString = Object.prototype.toString\n\nfunction isFunction (fn) {\n if (!fn) {\n return false\n }\n var string = toString.call(fn)\n return string === '[object Function]' ||\n (typeof fn === 'function' && string !== '[object RegExp]') ||\n (typeof window !== 'undefined' &&\n // IE8 and below\n (fn === window.setTimeout ||\n fn === window.alert ||\n fn === window.confirm ||\n fn === window.prompt))\n};\n","var trim = function(string) {\n return string.replace(/^\\s+|\\s+$/g, '');\n}\n , isArray = function(arg) {\n return Object.prototype.toString.call(arg) === '[object Array]';\n }\n\nmodule.exports = function (headers) {\n if (!headers)\n return {}\n\n var result = {}\n\n var headersArr = trim(headers).split('\\n')\n\n for (var i = 0; i < headersArr.length; i++) {\n var row = headersArr[i]\n var index = row.indexOf(':')\n , key = trim(row.slice(0, index)).toLowerCase()\n , value = trim(row.slice(index + 1))\n\n if (typeof(result[key]) === 'undefined') {\n result[key] = value\n } else if (isArray(result[key])) {\n result[key].push(value)\n } else {\n result[key] = [ result[key], value ]\n }\n }\n\n return result\n}\n","module.exports = extend\n\nvar hasOwnProperty = Object.prototype.hasOwnProperty;\n\nfunction extend() {\n var target = {}\n\n for (var i = 0; i < arguments.length; i++) {\n var source = arguments[i]\n\n for (var key in source) {\n if (hasOwnProperty.call(source, key)) {\n target[key] = source[key]\n }\n }\n }\n\n return target\n}\n","\"use strict\";\nvar window = require(\"global/window\")\nvar isFunction = require(\"is-function\")\nvar parseHeaders = require(\"parse-headers\")\nvar xtend = require(\"xtend\")\n\nmodule.exports = createXHR\n// Allow use of default import syntax in TypeScript\nmodule.exports.default = createXHR;\ncreateXHR.XMLHttpRequest = window.XMLHttpRequest || noop\ncreateXHR.XDomainRequest = \"withCredentials\" in (new createXHR.XMLHttpRequest()) ? createXHR.XMLHttpRequest : window.XDomainRequest\n\nforEachArray([\"get\", \"put\", \"post\", \"patch\", \"head\", \"delete\"], function(method) {\n createXHR[method === \"delete\" ? \"del\" : method] = function(uri, options, callback) {\n options = initParams(uri, options, callback)\n options.method = method.toUpperCase()\n return _createXHR(options)\n }\n})\n\nfunction forEachArray(array, iterator) {\n for (var i = 0; i < array.length; i++) {\n iterator(array[i])\n }\n}\n\nfunction isEmpty(obj){\n for(var i in obj){\n if(obj.hasOwnProperty(i)) return false\n }\n return true\n}\n\nfunction initParams(uri, options, callback) {\n var params = uri\n\n if (isFunction(options)) {\n callback = options\n if (typeof uri === \"string\") {\n params = {uri:uri}\n }\n } else {\n params = xtend(options, {uri: uri})\n }\n\n params.callback = callback\n return params\n}\n\nfunction createXHR(uri, options, callback) {\n options = initParams(uri, options, callback)\n return _createXHR(options)\n}\n\nfunction _createXHR(options) {\n if(typeof options.callback === \"undefined\"){\n throw new Error(\"callback argument missing\")\n }\n\n var called = false\n var callback = function cbOnce(err, response, body){\n if(!called){\n called = true\n options.callback(err, response, body)\n }\n }\n\n function readystatechange() {\n if (xhr.readyState === 4) {\n setTimeout(loadFunc, 0)\n }\n }\n\n function getBody() {\n // Chrome with requestType=blob throws errors arround when even testing access to responseText\n var body = undefined\n\n if (xhr.response) {\n body = xhr.response\n } else {\n body = xhr.responseText || getXml(xhr)\n }\n\n if (isJson) {\n try {\n body = JSON.parse(body)\n } catch (e) {}\n }\n\n return body\n }\n\n function errorFunc(evt) {\n clearTimeout(timeoutTimer)\n if(!(evt instanceof Error)){\n evt = new Error(\"\" + (evt || \"Unknown XMLHttpRequest Error\") )\n }\n evt.statusCode = 0\n return callback(evt, failureResponse)\n }\n\n // will load the data & process the response in a special response object\n function loadFunc() {\n if (aborted) return\n var status\n clearTimeout(timeoutTimer)\n if(options.useXDR && xhr.status===undefined) {\n //IE8 CORS GET successful response doesn't have a status field, but body is fine\n status = 200\n } else {\n status = (xhr.status === 1223 ? 204 : xhr.status)\n }\n var response = failureResponse\n var err = null\n\n if (status !== 0){\n response = {\n body: getBody(),\n statusCode: status,\n method: method,\n headers: {},\n url: uri,\n rawRequest: xhr\n }\n if(xhr.getAllResponseHeaders){ //remember xhr can in fact be XDR for CORS in IE\n response.headers = parseHeaders(xhr.getAllResponseHeaders())\n }\n } else {\n err = new Error(\"Internal XMLHttpRequest Error\")\n }\n return callback(err, response, response.body)\n }\n\n var xhr = options.xhr || null\n\n if (!xhr) {\n if (options.cors || options.useXDR) {\n xhr = new createXHR.XDomainRequest()\n }else{\n xhr = new createXHR.XMLHttpRequest()\n }\n }\n\n var key\n var aborted\n var uri = xhr.url = options.uri || options.url\n var method = xhr.method = options.method || \"GET\"\n var body = options.body || options.data\n var headers = xhr.headers = options.headers || {}\n var sync = !!options.sync\n var isJson = false\n var timeoutTimer\n var failureResponse = {\n body: undefined,\n headers: {},\n statusCode: 0,\n method: method,\n url: uri,\n rawRequest: xhr\n }\n\n if (\"json\" in options && options.json !== false) {\n isJson = true\n headers[\"accept\"] || headers[\"Accept\"] || (headers[\"Accept\"] = \"application/json\") //Don't override existing accept header declared by user\n if (method !== \"GET\" && method !== \"HEAD\") {\n headers[\"content-type\"] || headers[\"Content-Type\"] || (headers[\"Content-Type\"] = \"application/json\") //Don't override existing accept header declared by user\n body = JSON.stringify(options.json === true ? body : options.json)\n }\n }\n\n xhr.onreadystatechange = readystatechange\n xhr.onload = loadFunc\n xhr.onerror = errorFunc\n // IE9 must have onprogress be set to a unique function.\n xhr.onprogress = function () {\n // IE must die\n }\n xhr.onabort = function(){\n aborted = true;\n }\n xhr.ontimeout = errorFunc\n xhr.open(method, uri, !sync, options.username, options.password)\n //has to be after open\n if(!sync) {\n xhr.withCredentials = !!options.withCredentials\n }\n // Cannot set timeout with sync request\n // not setting timeout on the xhr object, because of old webkits etc. not handling that correctly\n // both npm's request and jquery 1.x use this kind of timeout, so this is being consistent\n if (!sync && options.timeout > 0 ) {\n timeoutTimer = setTimeout(function(){\n if (aborted) return\n aborted = true//IE9 may still call readystatechange\n xhr.abort(\"timeout\")\n var e = new Error(\"XMLHttpRequest timeout\")\n e.code = \"ETIMEDOUT\"\n errorFunc(e)\n }, options.timeout )\n }\n\n if (xhr.setRequestHeader) {\n for(key in headers){\n if(headers.hasOwnProperty(key)){\n xhr.setRequestHeader(key, headers[key])\n }\n }\n } else if (options.headers && !isEmpty(options.headers)) {\n throw new Error(\"Headers cannot be set on an XDomainRequest object\")\n }\n\n if (\"responseType\" in options) {\n xhr.responseType = options.responseType\n }\n\n if (\"beforeSend\" in options &&\n typeof options.beforeSend === \"function\"\n ) {\n options.beforeSend(xhr)\n }\n\n // Microsoft Edge browser sends \"undefined\" when send is called with undefined value.\n // XMLHttpRequest spec says to pass null as body to indicate no body\n // See https://github.com/naugtur/xhr/issues/100.\n xhr.send(body || null)\n\n return xhr\n\n\n}\n\nfunction getXml(xhr) {\n // xhr.responseXML will throw Exception \"InvalidStateError\" or \"DOMException\"\n // See https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/responseXML.\n try {\n if (xhr.responseType === \"document\") {\n return xhr.responseXML\n }\n var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === \"parsererror\"\n if (xhr.responseType === \"\" && !firefoxBugTakenEffect) {\n return xhr.responseXML\n }\n } catch (e) {}\n\n return null\n}\n\nfunction noop() {}\n","let lastError = '';\n\n/**\n * Creates the HTLM for a failure message\n * @param {string} canvasContainerId id of container of th\n * canvas.\n * @return {string} The html.\n */\nfunction makeFailHTML(msg) {\n return `\n\n
\n
\n
` + msg + `
\n
\n
\n`;\n}\n\n/**\n * Message for getting a webgl browser\n * @type {string}\n */\nlet GET_A_WEBGL_BROWSER = `\n\tThis page requires a browser that supports WebGL.
\n\tClick here to upgrade your browser.\n`;\n\n/**\n * Message for need better hardware\n * @type {string}\n */\nlet OTHER_PROBLEM = `\n\tIt does not appear your computer can support WebGL.
\n\tClick here for more information.\n`;\n\n/**\n * Code to return in `onError` callback when the browser doesn't support webgl\n * @type {number}\n */\nexport const ERROR_BROWSER_SUPPORT = 1;\n\n/**\n * Code to return in `onError` callback there's any other problem related to webgl\n * @type {number}\n */\nexport const ERROR_OTHER = 2;\n\n/**\n * Creates a webgl context. If creation fails it will\n * change the contents of the container of the \n * tag to an error message with the correct links for WebGL,\n * unless `onError` option is defined to a callback,\n * which allows for custom error handling..\n * @param {Element} canvas. The canvas element to create a\n * context from.\n * @param {WebGLContextCreationAttributes} optAttribs Any\n * creation attributes you want to pass in.\n * @return {WebGLRenderingContext} The created context.\n */\nexport function setupWebGL (canvas, optAttribs, onError) {\n function showLink(str) {\n let container = canvas.parentNode;\n if (container) {\n container.innerHTML = makeFailHTML(str);\n }\n }\n\n function handleError(errorCode, msg) {\n if (typeof onError === 'function') {\n onError(errorCode);\n } else {\n showLink(msg);\n }\n }\n\n if (!window.WebGLRenderingContext) {\n handleError(ERROR_BROWSER_SUPPORT, GET_A_WEBGL_BROWSER);\n return null;\n }\n\n let context = create3DContext(canvas, optAttribs);\n if (!context) {\n handleError(ERROR_OTHER, OTHER_PROBLEM);\n } else {\n context.getExtension('OES_standard_derivatives');\n }\n return context;\n}\n\n/**\n * Creates a webgl context.\n * @param {!Canvas} canvas The canvas tag to get context\n * from. If one is not passed in one will be created.\n * @return {!WebGLContext} The created context.\n */\nexport function create3DContext(canvas, optAttribs) {\n let names = ['webgl', 'experimental-webgl'];\n let context = null;\n for (var ii = 0; ii < names.length; ++ii) {\n try {\n context = canvas.getContext(names[ii], optAttribs);\n } catch(e) {\n if (context) {\n break;\n }\n }\n }\n return context;\n}\n\n/*\n *\tCreate a Vertex of a specific type (gl.VERTEX_SHADER/)\n */\nexport function createShader(main, source, type, offset) {\n let gl = main.gl;\n\n let shader = gl.createShader(type);\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n\n let compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);\n\n if (!compiled) {\n // Something went wrong during compilation; get the error\n lastError = gl.getShaderInfoLog(shader);\n console.error('*** Error compiling shader ' + shader + ':' + lastError);\n main.trigger('error', {\n shader: shader,\n source: source,\n type: type,\n error: lastError,\n offset: offset || 0\n });\n gl.deleteShader(shader);\n return null;\n }\n\n return shader;\n}\n\n/**\n * Loads a shader.\n * @param {!WebGLContext} gl The WebGLContext to use.\n * @param {string} shaderSource The shader source.\n * @param {number} shaderType The type of shader.\n * @param {function(string): void) opt_errorCallback callback for errors.\n * @return {!WebGLShader} The created shader.\n */\nexport function createProgram(main, shaders, optAttribs, optLocations) {\n let gl = main.gl;\n\n let program = gl.createProgram();\n for (let ii = 0; ii < shaders.length; ++ii) {\n gl.attachShader(program, shaders[ii]);\n }\n if (optAttribs) {\n for (let ii = 0; ii < optAttribs.length; ++ii) {\n gl.bindAttribLocation(\n program,\n optLocations ? optLocations[ii] : ii,\n optAttribs[ii]);\n }\n }\n gl.linkProgram(program);\n\n // Check the link status\n let linked = gl.getProgramParameter(program, gl.LINK_STATUS);\n if (!linked) {\n // something went wrong with the link\n lastError = gl.getProgramInfoLog(program);\n console.log('Error in program linking:' + lastError);\n gl.deleteProgram(program);\n return null;\n }\n return program;\n}\n\n// By Brett Camber on\n// https://github.com/tangrams/tangram/blob/master/src/gl/glsl.js\nexport function parseUniforms(uniforms, prefix = null) {\n let parsed = [];\n\n for (let name in uniforms) {\n let uniform = uniforms[name];\n let u;\n\n if (prefix) {\n name = prefix + '.' + name;\n }\n\n // Single float\n if (typeof uniform === 'number') {\n parsed.push({\n type: 'float',\n method: '1f',\n name,\n value: uniform\n });\n }\n // Array: vector, array of floats, array of textures, or array of structs\n else if (Array.isArray(uniform)) {\n // Numeric values\n if (typeof uniform[0] === 'number') {\n // float vectors (vec2, vec3, vec4)\n if (uniform.length === 1) {\n parsed.push({\n type: 'float',\n method: '1f',\n name,\n value: uniform\n });\n }\n // float vectors (vec2, vec3, vec4)\n else if (uniform.length >= 2 && uniform.length <= 4) {\n parsed.push({\n type: 'vec' + uniform.length,\n method: uniform.length + 'fv',\n name,\n value: uniform\n });\n }\n // float array\n else if (uniform.length > 4) {\n parsed.push({\n type: 'float[]',\n method: '1fv',\n name: name + '[0]',\n value: uniform\n });\n }\n // TODO: assume matrix for (typeof == Float32Array && length == 16)?\n }\n // Array of textures\n else if (typeof uniform[0] === 'string') {\n parsed.push({\n type: 'sampler2D',\n method: '1i',\n name: name,\n value: uniform\n });\n }\n // Array of arrays - but only arrays of vectors are allowed in this case\n else if (Array.isArray(uniform[0]) && typeof uniform[0][0] === 'number') {\n // float vectors (vec2, vec3, vec4)\n if (uniform[0].length >= 2 && uniform[0].length <= 4) {\n // Set each vector in the array\n for (u = 0; u < uniform.length; u++) {\n parsed.push({\n type: 'vec' + uniform[0].length,\n method: uniform[u].length + 'fv',\n name: name + '[' + u + ']',\n value: uniform[u]\n });\n }\n }\n // else error?\n }\n // Array of structures\n else if (typeof uniform[0] === 'object') {\n for (u = 0; u < uniform.length; u++) {\n // Set each struct in the array\n parsed.push(...parseUniforms(uniform[u], name + '[' + u + ']'));\n }\n }\n }\n // Boolean\n else if (typeof uniform === 'boolean') {\n parsed.push({\n type: 'bool',\n method: '1i',\n name,\n value: uniform\n });\n }\n // Texture\n else if (typeof uniform === 'string') {\n parsed.push({\n type: 'sampler2D',\n method: '1i',\n name,\n value: uniform\n });\n }\n // Structure\n else if (typeof uniform === 'object') {\n // Set each field in the struct\n parsed.push(...parseUniforms(uniform, name));\n }\n // TODO: support other non-float types? (int, etc.)\n }\n return parsed;\n}\n","export function isCanvasVisible(canvas) {\n let bound = canvas.getBoundingClientRect();\n return\t((bound.top + bound.height) > 0) &&\n (bound.top < (window.innerHeight || document.documentElement.clientHeight));\n}\n\nexport function isPowerOf2(value) {\n return (value & (value - 1)) === 0;\n}\n\nexport function isSafari () {\n return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n};\n\nexport function nextHighestPowerOfTwo(x) {\n --x;\n for (let i = 1; i < 32; i <<= 1) {\n x = x | x >> i;\n }\n return x + 1;\n}\n\nexport function FormatNumberLength(num, length) {\n let r = num.toString();\n while (r.length < length) {\n r = '0' + r;\n }\n return r;\n}\n\nexport function getMousePos(canvas, evt) {\n let rect = canvas.getBoundingClientRect();\n return {\n x: evt.clientX - rect.left,\n y: evt.clientY - rect.top\n };\n}\n\nexport function isDiff(a, b) {\n if (a && b) {\n return a.toString() !== b.toString();\n }\n return false;\n}\n\nexport function getFile(url) {\n let httpRequest = new XMLHttpRequest();\n httpRequest.open(\"GET\", url, false);\n httpRequest.send();\n if (httpRequest.status == 200)\n return httpRequest.responseText;\n else\n return \"\";\n}\n\nexport function subscribeMixin (target) {\n var listeners = new Set();\n\n return Object.assign(target, {\n\n subscribe(listener) {\n listeners.add(listener);\n },\n\n on(type, f) {\n let listener = {};\n listener[type] = f;\n listeners.add(listener);\n },\n\n unsubscribe(listener) {\n listeners.delete(listener);\n },\n\n unsubscribeAll() {\n listeners.clear();\n },\n\n trigger(event, ...data) {\n for (var listener of listeners) {\n if (typeof listener[event] === 'function') {\n listener[event](...data);\n }\n }\n }\n });\n}\n","export function subscribeMixin (target) {\n var listeners = new Set();\n\n return Object.assign(target, {\n\n on(type, f) {\n let listener = {};\n listener[type] = f;\n listeners.add(listener);\n },\n\n off(type, f) {\n if (f) {\n let listener = {};\n listener[type] = f;\n listeners.delete(listener);\n }\n else {\n for (let item of listeners) {\n for (let key of Object.keys(item)) {\n if (key === type) {\n listeners.delete(item);\n return;\n }\n }\n }\n }\n },\n\n listSubscriptions() {\n for (let item of listeners) {\n console.log(item);\n }\n },\n\n subscribe(listener) {\n listeners.add(listener);\n },\n\n unsubscribe(listener) {\n listeners.delete(listener);\n },\n\n unsubscribeAll() {\n listeners.clear();\n },\n\n trigger(event, ...data) {\n for (var listener of listeners) {\n if (typeof listener[event] === 'function') {\n listener[event](...data);\n }\n }\n }\n });\n}\n","// Texture management\nimport { isPowerOf2, isSafari } from '../tools/common';\nimport { subscribeMixin } from '../tools/mixin';\n\n// GL texture wrapper object for keeping track of a global set of textures, keyed by a unique user-defined name\nexport default class Texture {\n constructor(gl, name, options = {}) {\n subscribeMixin(this);\n\n this.gl = gl;\n this.texture = gl.createTexture();\n if (this.texture) {\n this.valid = true;\n }\n this.bind();\n\n this.name = name;\n this.source = null;\n this.sourceType = null;\n this.loading = null; // a Promise object to track the loading state of this texture\n\n // Default to a 1-pixel black texture so we can safely render while we wait for an image to load\n // See: http://stackoverflow.com/questions/19722247/webgl-wait-for-texture-to-load\n this.setData(1, 1, new Uint8Array([0, 0, 0, 255]), { filtering: 'linear' });\n this.setFiltering(options.filtering);\n\n this.load(options);\n }\n\n // Destroy a single texture instance\n destroy() {\n if (!this.valid) {\n return;\n }\n this.gl.deleteTexture(this.texture);\n this.texture = null;\n delete this.data;\n this.data = null;\n this.valid = false;\n }\n\n bind(unit) {\n if (!this.valid) {\n return;\n }\n if (typeof unit === 'number') {\n if (Texture.activeUnit !== unit) {\n this.gl.activeTexture(this.gl.TEXTURE0 + unit);\n Texture.activeUnit = unit;\n }\n }\n if (Texture.activeTexture !== this.texture) {\n this.gl.bindTexture(this.gl.TEXTURE_2D, this.texture);\n Texture.activeTexture = this.texture;\n }\n }\n\n load(options = {}) {\n this.loading = null;\n\n if (typeof options.url === 'string') {\n if (this.url === undefined || options.url !== this.url) {\n this.setUrl(options.url, options);\n }\n }\n else if (options.element) {\n this.setElement(options.element, options);\n }\n else if (options.data && options.width && options.height) {\n this.setData(options.width, options.height, options.data, options);\n }\n }\n\n // Sets texture from an url\n setUrl(url, options = {}) {\n if (!this.valid) {\n return;\n }\n\n this.url = url; // save URL reference (will be overwritten when element is loaded below)\n this.source = this.url;\n this.sourceType = 'url';\n\n this.loading = new Promise((resolve, reject) => {\n let ext = url.split('.').pop().toLowerCase();\n let isVideo = (ext === 'ogv' || ext === 'webm' || ext === 'mp4');\n\n let element = undefined\n if (isVideo) {\n element = document.createElement('video');\n element.autoplay = true;\n \n \n element.muted = true; /* required for modern browsers to autoplay video */\n setTimeout(function () {\n element.play() /* doesn't block promise but needs a more elegant solution */\n }, 1);\n \n options.filtering = 'nearest';\n // element.preload = 'auto';\n // element.style.display = 'none';\n // document.body.appendChild(element);\n } else {\n element = new Image();\n }\n\n element.onload = () => {\n try {\n this.setElement(element, options);\n }\n catch (e) {\n console.log(`Texture '${this.name}': failed to load url: '${this.source}'`, e, options);\n }\n resolve(this);\n };\n element.onerror = e => {\n // Warn and resolve on error\n console.log(`Texture '${this.name}': failed to load url: '${this.source}'`, e, options);\n resolve(this);\n };\n\n // Safari has a bug loading data-URL elements with CORS enabled, so it must be disabled in that case\n // https://bugs.webkit.org/show_bug.cgi?id=123978\n if (!(isSafari() && this.source.slice(0, 5) === 'data:')) {\n element.crossOrigin = 'anonymous';\n }\n\n element.src = this.source;\n if (isVideo) {\n this.setElement(element, options);\n }\n });\n return this.loading;\n }\n\n // Sets texture to a raw image buffer\n setData(width, height, data, options = {}) {\n this.width = width;\n this.height = height;\n\n this.source = data;\n this.sourceType = 'data';\n\n this.update(options);\n this.setFiltering(options);\n\n this.loading = Promise.resolve(this);\n return this.loading;\n }\n\n // Sets the texture to track a element (canvas/image)\n setElement(element, options) {\n let el = element;\n\n // a string element is interpeted as a CSS selector\n if (typeof element === 'string') {\n element = document.querySelector(element);\n }\n\n if (element instanceof HTMLCanvasElement ||\n element instanceof HTMLImageElement ||\n element instanceof HTMLVideoElement) {\n this.source = element;\n this.sourceType = 'element';\n\n if (element instanceof HTMLVideoElement) {\n this.width = this.source.videoWidth;\n this.height = this.source.videoHeight;\n element.addEventListener('canplaythrough', () => {\n this.intervalID = setInterval(()=>{\n this.update(options);\n }, 15);\n }, true);\n element.addEventListener('ended', () => {\n element.currentTime = 0;\n element.play();\n }, true);\n } else {\n this.update(options);\n } \n this.setFiltering(options);\n }\n else {\n let msg = `the 'element' parameter (\\`element: ${JSON.stringify(el)}\\`) must be a CSS `;\n msg += `selector string, or a , or