// DymicoScript v4m2 runtime (no grooscript gs.*; iOS 13.0 / old-WebView safe) var D$ = (typeof D$ !== 'undefined') ? D$ : (function(){ var isArr = Array.isArray; function isPlain(x){ if (x == null || typeof x !== 'object') return false; var p = Object.getPrototypeOf(x); return p === Object.prototype || p === null; } function truthy(x){ if (x == null) return false; if (isArr(x)) return x.length > 0; if (typeof x === 'string') return x.length > 0; if (typeof x === 'number') return x !== 0; if (isPlain(x)) return Object.keys(x).length > 0; // An EMPTY collection is falsey in Groovy, and `as Set` / new HashSet() are real JS // Sets, which are neither arrays nor plain objects -- so an empty one read TRUE [v4m58]. if (typeof Set !== 'undefined' && (x instanceof Set || x instanceof Map)) return x.size > 0; return !!x; } function eq(a,b){ if (a === b) return true; if (a == null || b == null) return a == b; // A Set is UNORDERED, and JSON.stringify renders EVERY Set as {} -- so the structural // branch below made ([1] as Set) == ([2] as Set) true. Compare membership [v4m58]. if (typeof Set !== 'undefined' && (a instanceof Set || b instanceof Set)) { if (!(a instanceof Set) || !(b instanceof Set) || a.size !== b.size) return false; var same = true; a.forEach(function(v){ if (same && !b.has(v)) same = false; }); return same; } if (typeof a === 'object' && typeof b === 'object') { try { return JSON.stringify(a) === JSON.stringify(b); } catch(e) { return false; } } return a == b; } function cmp(a,b){ if (a == null && b == null) return 0; if (a == null) return -1; if (b == null) return 1; return a < b ? -1 : (a > b ? 1 : 0); } function entries(m){ var r = [], k; for (k in m) if (Object.prototype.hasOwnProperty.call(m, k)) r.push({key: k, value: m[k]}); return r; } function callE(f, e, i){ return f.length >= 2 ? f(e.key, e.value, i) : f(e, i); } // receivers with their OWN method (or Groovy methodMissing -- o-broker proxies!) win function own(x, n){ if (x == null || isArr(x) || typeof x === 'string') return false; if (typeof x[n] === 'function') return true; // plain-object accessor (o.dcMessage -> {find,findAll,new...}) delegates to its real method, not GDK map-collection logic return !isPlain(x) && typeof x.methodMissing === 'function'; } // Built-ins every JS function carries. The static-through-instance fallback must skip // these: gs.map's minified ctor `q` has .length = 0 (arity), which made // `graphData.length == 0` true on a NON-empty map (RXME Admin dashboard breaker). // 'caller'/'arguments' also THROW on access for strict-mode class constructors. var FN_BUILTINS = { length: 1, name: 1, prototype: 1, caller: 1, arguments: 1 }; // forward ALL original call args (D$ helper signatures are narrower than e.g. // forerunner's find(query, options, cb)); fall back to methodMissing dispatch // Groovy OPERATOR OVERLOADING: a class defining plus/minus/multiply/div/mod/leftShift/ // rightShift takes precedence over the built-in rule for that operator [v4m55]. // Deliberately NOT own(): own() also accepts methodMissing, which would turn `proxy + x` // into a remote `plus` call on the o broker. Maps and arrays keep their own semantics. function opOv(a, n){ return a != null && typeof a === 'object' && !isArr(a) && !isPlain(a) && !(a instanceof Date) && !(a instanceof Set) && typeof a[n] === 'function'; } function ownCall(c, n, args){ var rest = Array.prototype.slice.call(args, 1); var f = c[n]; if (typeof f === 'function') return f.apply(c, rest); var r = c.methodMissing(n, rest); return (r === undefined || r === null) ? c : r; } // gs parity: proxies chain (.add(x).do()) function gp(o,p){ if (o == null) return null; // Groovy IMPLICIT SPREAD: list.foo means list*.foo. A REAL List property still wins -- // [1,2].size is 2, not [null,null] -- but a METHOD name does not ([[a:1]].keySet is // [null] in real Groovy). A missing key on an element yields null, so // [[a:1],[b:2]].a is [1, null], and it chains: [[a:[b:1]]].a.b is [1] [v4m43]. if (isArr(o)) { if (p === 'size') return o.length; var _av = o[p]; if (_av !== undefined) return _av; return o.map(function(_e){ return _e == null ? null : gp(_e, p); }); } if (typeof o === 'object' && !isArr(o) && !isPlain(o) && typeof o.getProperty === 'function') return o.getProperty(p); var v = o[p]; // Groovy reads a property THROUGH ITS GETTER whenever one exists: o.foo IS o.getFoo() / // o.isFoo(), and a bare field read only when neither is defined. Preferring the field // and falling back to the getter only when it was undefined returned the RAW field for // every class carrying both -- a silent wrong answer, never an error [v4m58]. It also // keeps working for the no-such-field cases it always handled (Date.time -> getTime(), // map.empty -> isEmpty()). Maps (isPlain) and arrays keep key/index semantics, and a // non-string key -- subscripts route here too -- can never name a getter. if (typeof o === 'object' && !isArr(o) && !isPlain(o) && typeof p === 'string' && p.length > 0) { var _gc = p.charAt(0).toUpperCase() + p.slice(1); var _gg = o['get' + _gc]; if (typeof _gg === 'function') return _gg.call(o); var _gi = o['is' + _gc]; if (typeof _gi === 'function') return _gi.call(o); if (v === undefined) { // Groovy resolves statics through instances (startupParams.staticField) -- but only // USER statics, never Function built-ins (length/name/prototype/...) if (o.constructor && !FN_BUILTINS[p] && o.constructor[p] !== undefined) return o.constructor[p]; // Groovy propertyMissing hook (the o broker/ObjectFinder resolves services this way) if (typeof o.propertyMissing === 'function') return o.propertyMissing(p); } } return v; } // Every collection GDK helper funnels through here. JS Set/Map (Groovy HashSet/HashMap // ctors) MUST spread to elements -- the [c] fallback wrapped a whole Set so // `topicsSet.sort().collect { it.toLowerCase() }` saw the SET as the element (v4m29). function toArr(c){ if (c == null) return []; if (isArr(c)) return c; if (typeof c === 'string') return c.split(''); if (c instanceof Set) return Array.from(c); if (c instanceof Map) { var r = []; c.forEach(function(v,k){ r.push({key: k, value: v}); }); return r; } if (isPlain(c)) return entries(c); return [c]; } function str(x){ if (x == null) return 'null'; if (typeof x === 'string') return x; if (isArr(x)) { return '[' + x.map(str).join(', ') + ']'; } if (isPlain(x)) { var ks = Object.keys(x); if (!ks.length) return '[:]'; return '[' + ks.map(function(k){ return k + ':' + str(x[k]); }).join(', ') + ']'; } // Groovy prints a Set like a list; String(set) is the useless "[object Set]" [v4m58]. if (typeof Set !== 'undefined' && x instanceof Set) return '[' + Array.from(x).map(str).join(', ') + ']'; return String(x); } // Mirrors the emitter's GDK_ROUTED set. The emitter rewrites these to D$. when it // can see the call site, but dynamic dispatch (notably list*.foo()) arrives at mc instead, // so mc needs the same routing as a last resort before it gives up [v4m44]. var GDKN = { each:1, eachWithIndex:1, collect:1, findAll:1, find:1, any:1, every:1, sum:1, inject:1, join:1, contains:1, containsKey:1, keySet:1, values:1, size:1, length:1, sort:1, unique:1, first:1, last:1, reverse:1, flatten:1, collectMany:1, min:1, max:1, count:1, groupBy:1, take:1, drop:1, add:1, addAll:1, putAll:1, remove:1, removeAll:1, clear:1, replaceAll:1, tokenize:1, padLeft:1, padRight:1, isNumber:1, toInteger:1, toFloat:1, toDouble:1, toBoolean:1, times:1, capitalize:1, uncapitalize:1 }; var D = { truthy: truthy, eq: eq, cmp: cmp, str: str, isPlain: isPlain, gp: gp, sp: function(o,k){ if (o == null) return null; var v = gp(o,k); return v === undefined ? null : v; }, // `x.await()` receiver [v4m50]: o-broker call proxies (OObject/NestedO) carry an @GsNative // await() that returns a Promise; a Promise (Promise.all([..]).await()) or plain value // is awaited as-is. Checked on `await`, not `then` -- OObject has its own then(). aw: function(x){ if (x != null && typeof x.await === 'function') return x.await(); return x; }, // Groovy shallow clone (VueComponent.notify: `notifyParams.clone() << map`) [v4m28]. // Own clone() wins (gs maps carry one); arrays slice; plain maps shallow-copy. clone: function(x){ if (x == null) return null; if (isArr(x)) return x.slice(); if (typeof x === 'object' && typeof x.clone === 'function') return x.clone(); if (x instanceof Date) return new Date(x.getTime()); if (isPlain(x)) return Object.assign({}, x); return x; }, // Groovy String.capitalize/uncapitalize (no JS equivalent; DataViewer topic labels) [v4m29] capitalize: function(s){ if (s == null) return s; s = String(s); return s.length ? s.charAt(0).toUpperCase() + s.slice(1) : s; }, uncapitalize: function(s){ if (s == null) return s; s = String(s); return s.length ? s.charAt(0).toLowerCase() + s.slice(1) : s; }, // Groovy GDK Date.format(pattern) -- java.text.SimpleDateFormat subset [v4m36]. // grooscript's gs.date() attached a format() to every date IT built; V4 emits a plain // `new Date(...)`, so `date.format('dd/MM/yyyy HH:mm')` fell through mc to the throw. // Coldwatch Admin breaker: CwNotificationsComponent.formatDate threw 249x and the whole // notifications list rendered empty (Dashboard.formatDate too). // SimpleDateFormat tokens, NOT moment tokens -- moment objects carry their own .format() // and are taken by mc's own-method-first branch long before this fallback is reached. dfmt: function(d, p){ if (d == null) return null; if (p == null) return String(d); var MON = ['January','February','March','April','May','June','July','August','September','October','November','December']; var DAY = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']; function pad(n,w){ var s = String(Math.abs(n)); while (s.length < w) s = '0' + s; return (n < 0 ? '-' : '') + s; } var y = d.getFullYear(), M = d.getMonth(), da = d.getDate(), H = d.getHours(); var mi = d.getMinutes(), se = d.getSeconds(), ms = d.getMilliseconds(), dw = d.getDay(); var h12 = H % 12; if (h12 === 0) h12 = 12; var tok = { 'yyyy': pad(y,4), 'yy': pad(y % 100,2), 'y': String(y), 'MMMM': MON[M], 'MMM': MON[M].slice(0,3), 'MM': pad(M+1,2), 'M': String(M+1), 'dd': pad(da,2), 'd': String(da), 'EEEE': DAY[dw], 'EEE': DAY[dw].slice(0,3), 'HH': pad(H,2), 'H': String(H), 'hh': pad(h12,2), 'h': String(h12), 'mm': pad(mi,2), 'm': String(mi), 'ss': pad(se,2), 's': String(se), 'SSS': pad(ms,3), 'S': String(ms), 'a': (H < 12 ? 'AM' : 'PM') }; var out = '', i = 0, s = String(p); while (i < s.length) { var c = s.charAt(i); if (c === "'") { // SimpleDateFormat quoted literal ('' = one quote) if (s.charAt(i+1) === "'") { out += "'"; i += 2; continue; } var e = s.indexOf("'", i+1); if (e === -1) { out += s.slice(i+1); break; } out += s.slice(i+1, e); i = e + 1; continue; } if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { var j = i; while (j < s.length && s.charAt(j) === c) j++; // longest run of one letter var m = s.slice(i, j); while (m.length > 0 && tok[m] === undefined) m = m.slice(0, m.length - 1); if (m.length > 0) { out += tok[m]; i += m.length; continue; } out += s.slice(i, j); i = j; continue; // unknown letter: passthrough } out += c; i++; } return out; }, // Groovy `+`: list+list concat / list+elem append / map+map merge / Set union; // numbers & strings fall through to JS + (fast path first) [v4m29: // `["all"] + topicsSet.sort()` string-coerced under raw JS +]. plus: function(a,b){ if (typeof a === 'number') return a + b; if (opOv(a,'plus')) return a.plus(b); // Groovy String + collection uses the value's GROOVY toString: "x" + [a:1] is "x[a:1]" // and "x" + [1,null] is "x[1, null]" -- NOT "x[object Object]" and "x1,". str() has // always rendered both correctly; it simply never saw them, because this line // concatenated first and handed str() a finished string. GString interpolation went // through str() directly and was right all along, so the two spellings disagreed: // "v:${m}" was correct while "v:" + m was not [v4m42]. Found via the Company product, // whose auth diagnostics log a map. Numbers/booleans/null keep the raw JS path so // "a" + null stays "anull"; Dates and gs maps fall to str's String(x) tail unchanged. if (typeof a === 'string') return a + ((b == null || typeof b !== 'object') ? b : str(b)); // Groovy Date + int = plus N DAYS. Raw JS `+` string-concats a Date [v4m37]. if (a instanceof Date && typeof b === 'number') return new Date(a.getTime() + b * 86400000); if (isArr(a)) return a.concat(isArr(b) ? b : (b instanceof Set ? Array.from(b) : [b])); if (a instanceof Set) { var s = new Set(a); if (isArr(b) || b instanceof Set) { (isArr(b) ? b : Array.from(b)).forEach(function(v){ s.add(v); }); } else { s.add(b); } return s; } // Groovy Map + Map. Do NOT require isPlain on both sides: a socket-borne grooscript map // (gs.toGroovy is redefined by the bundle's own @GsNative, so server responses arrive as // REAL gs maps even on a V4 page) and Vue's $attrs proxy are object-like but NOT plain, // so they fell through to the `a + b` below and STRING-CONCATENATED to the 30-char // "[object Object][object Object]". Coldwatch I3MenuButton: btnProps became that string, // `` spread its char indices AND grooscript's ENUMERABLE // String.prototype polyfills onto the