返回首頁 

Greasy Fork is available in English.

YouTube RM3 - Reduce Memory Usage by Reusing Components

A simple tool that runs in the background to reuse YouTube components, thereby reducing memory usage over time.

  1. // ==UserScript==// @name YouTube RM3 - Reduce Memory Usage by Reusing Components// @namespace Violentmonkey Scripts// @version 0.1.0019// @license MIT// @match https://www.youtube.com/*// @match https://studio.youtube.com/live_chat*////// @author CY Fung// @run-at document-start// @grant none// @unwrap// @allFrames true// @inject-into page//// @compatible firefox Violentmonkey// @compatible firefox Tampermonkey// @compatible firefox FireMonkey// @compatible chrome Violentmonkey// @compatible chrome Tampermonkey// @compatible opera Violentmonkey// @compatible opera Tampermonkey// @compatible safari Stay// @compatible edge Violentmonkey// @compatible edge Tampermonkey// @compatible brave Violentmonkey// @compatible brave Tampermonkey//// @description A simple tool that runs in the background to reuse YouTube components, thereby reducing memory usage over time.// @description:en A simple tool that runs in the background to reuse YouTube components, thereby reducing memory usage over time.// @description:ja YouTubeコンポーネントを再利用することで、長期的なメモリ使用量の削減を目指す、バックグラウンドで実行されるシンプルなツールです。// @description:zh-TW 一個在背景執行的簡易工具,可重複利用 YouTube 元件,從而在長期減少記憶體使用量。// @description:zh-CN 一个在后台运行的简单工具,通过重复利用 YouTube 组件,从而在长期减少内存使用量。//// ==/UserScript==const rm3 = window.rm3 = {};// console.log(3001);(() => {const DEBUG_OPT = false;const CONFIRM_TIME = 4000;const CHECK_INTERVAL = 400;const DEBUG_dataChangeReflection = true;/** @type {globalThis.PromiseConstructor} */const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.// https://qiita.com/piroor/items/02885998c9f76f45bfa0// https://gist.github.com/piroor/829ecb32a52c2a42e5393bbeebe5e63ffunction uniq(array) {return [...new Set(array)];};rm3.uniq = uniq; // [[debug]]DEBUG_OPT && (rm3.location= location.href);rm3.inspect = () => {return uniq([...document.getElementsByTagName('*')].filter(e => e?.polymerController?.createComponent_).map(e => e.nodeName)); // [[debug]]}const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0);const indr = o => insp(o).$ || o.$ || 0;const getProto = (element) => {if (element) {const cnt = insp(element);return cnt.constructor.prototype || null;}return null;}const LinkedArray = (() => {class Node {constructor(value) {this.value = value;this.next = null;this.prev = null;}}class LinkedArray {constructor() {this.head = null;this.tail = null;this.length = 0;}push(value) {const newNode = new Node(value);if (this.length === 0) {this.head = newNode;this.tail = newNode;} else {this.tail.next = newNode;newNode.prev = this.tail;this.tail = newNode;}this.length++;return this.length;}pop() {if (this.length === 0) return undefined;const removedNode = this.tail;if (this.length === 1) {this.head = null;this.tail = null;} else {this.tail = removedNode.prev;this.tail.next = null;removedNode.prev = null;}this.length--;return removedNode.value;}unshift(value) {const newNode = new Node(value);if (this.length === 0) {this.head = newNode;this.tail = newNode;} else {newNode.next = this.head;this.head.prev = newNode;this.head = newNode;}this.length++;return this.length;}shift() {if (this.length === 0) return undefined;const removedNode = this.head;if (this.length === 1) {this.head = null;this.tail = null;} else {this.head = removedNode.next;this.head.prev = null;removedNode.next = null;}this.length--;return removedNode.value;}size() {return this.length;}// Get a node by index (0-based)getNode(index) {if (index < 0 || index >= this.length) return null;let current;let counter;// Optimization: start from closest endif (index < this.length / 2) {current = this.head;counter = 0;while (counter !== index) {current = current.next;counter++;}} else {current = this.tail;counter = this.length - 1;while (counter !== index) {current = current.prev;counter--;}}return current;}// Get value by indexget(index) {const node = this.getNode(index);return node ? node.value : undefined;}// Find the first node with the given value and return both node and indexfindNode(value) {let current = this.head;let idx = 0;while (current) {if (current.value === value) {return { node: current, index: idx };}current = current.next;idx++;}return { node: null, index: -1 };}toArray() {const arr = [];let current = this.head;while (current) {arr.push(current.value);current = current.next;}return arr;}// Insert a new value before a given node (provided you already have the node reference)insertBeforeNode(node, newValue) {if (!node) {this.unshift(newValue);return true;}if (node === this.head) {// If the target is the head, just unshiftthis.unshift(newValue);} else {const newNode = new Node(newValue);const prevNode = node.prev;prevNode.next = newNode;newNode.prev = prevNode;newNode.next = node;node.prev = newNode;this.length++;}return true;}// Insert a new value after a given node (provided you already have the node reference)insertAfterNode(node, newValue) {if (!node) {this.push(newValue);return true;}if (node === this.tail) {// If the target is the tail, just pushthis.push(newValue);} else {const newNode = new Node(newValue);const nextNode = node.next;node.next = newNode;newNode.prev = node;newNode.next = nextNode;nextNode.prev = newNode;this.length++;}return true;}// Insert a new value before the first occurrence of an existing value (search by value)insertBefore(existingValue, newValue) {const { node } = this.findNode(existingValue);if (!node) return false; // Not foundreturn this.insertBeforeNode(node, newValue);}// Insert a new value after the first occurrence of an existing value (search by value)insertAfter(existingValue, newValue) {const { node } = this.findNode(existingValue);if (!node) return false; // Not foundreturn this.insertAfterNode(node, newValue);}// Delete a given node from the listdeleteNode(node) {if (!node) return false;if (this.length === 1 && node === this.head && node === this.tail) {// Only one element in the listthis.head = null;this.tail = null;} else if (node === this.head) {// Node is the headthis.head = node.next;this.head.prev = null;node.next = null;} else if (node === this.tail) {// Node is the tailthis.tail = node.prev;this.tail.next = null;node.prev = null;} else {// Node is in the middleconst prevNode = node.prev;const nextNode = node.next;prevNode.next = nextNode;nextNode.prev = prevNode;node.prev = null;node.next = null;}this.length--;return true;}}LinkedArray.Node = Node;return LinkedArray;})();class LimitedSizeSet extends Set {constructor(n) {super();this.limit = n;}add(key) {if (!super.has(key)) {super.add(key);let n = super.size - this.limit;if (n > 0) {const iterator = super.values();do {const firstKey = iterator.next().value; // Get the first (oldest) keysuper.delete(firstKey); // Delete the oldest key} while (--n > 0)}}}removeAdd(key) {super.delete(key);this.add(key);}}if (!document.createElement9512 && typeof document.createElement === 'function' && document.createElement.length === 1) {// sizing of Map / Set. Shall limit ?const hookTos = new Set(); // [[debug]]DEBUG_OPT && (rm3.hookTos = hookTos);// const reusePool = new Map(); // xx858const entryRecords = new WeakMap(); // a weak link between element and record// rm3.list = [];const operations = rm3.operations = new Set(); // to find out the "oldest elements"const availablePools = rm3.availablePools = new Map(); // those "old elements" can be usedlet lastTimeCheck = 0;const reuseRecord_ = new LimitedSizeSet(256); // [[debug]]const reuseCount_ = new Map();let noTimeCheck = false;// const defaultValues = new Map();// const noValues = new Map();const timeCheck = () => {// regularly check elements are old enough to put into the available pools// note: the characterists of YouTube components are non-volatile. So don't need to waste time to check weakRef.deref() is null or not for removing in operations.const ct = Date.now();if (ct - lastTimeCheck < CHECK_INTERVAL || noTimeCheck) return;lastTimeCheck = ct;noTimeCheck = true;// 16,777,216if (hookTos.size > 777216) hookTos.clear(); // just debug usage, dont concernif (operations.size > 7777216) {// extremely old elements in operations mean they have no attach/detach action. so no reuse as well. they are just trash in memory.// as no checking of the weakRef.deref() being null or not, those trash could be already cleaned. However we don't concern this.// (not to count whether they are actual memory trash or not)const half = operations.size >>> 1;let i = 0;for (const value of operations) {if (i++ > half) break;operations.delete(value);}}// {// // smallest to largest// // past to recent// const iterator = operations[Symbol.iterator]();// console.log(1831, '------------------------')// while (true) {// const iteratorR###lt = iterator.next(); // 順番に値を取りだす// if (iteratorR###lt.done) break; // 取り出し終えたなら、break// console.log(1835, iteratorR###lt.value[3])// }// console.log(1839, '------------------------')// }// Set iterator// s.add(2) s.add(6) s.add(1) s.add(3)// next: 2 -> 6 -> 1 -> 3// op1 (oldest) -> op2 -> op3 -> op4 (latest)const iterator = operations[Symbol.iterator]();const targetTime = ct - CONFIRM_TIME;const pivotNodes = new WeakMap();while (true) {const iteratorR###lt = iterator.next(); // 順番に値を取りだすif (iteratorR###lt.done) break; // 取り出し終えたなら、breakconst entryRecord = iteratorR###lt.value;if (entryRecord[3] > targetTime) break;if (!entryRecord[4] && entryRecord[1] < 0 && entryRecord[2] > 0) {const element = entryRecord[0].deref();const eKey = (element || 0).__rm3Tag003__;if (!eKey) {operations.delete(entryRecord);} else if (element.isConnected === false && insp(element).isAttached === false) {entryRecord[4] = true;let availablePool = availablePools.get(eKey);if (!availablePool) availablePools.set(eKey, availablePool = new LinkedArray());if (!(availablePool instanceof LinkedArray)) throw new Error();DEBUG_OPT && console.log(3885,'add key', eKey, availablePools.size)// rm3.showSize = ()=>availablePools.size// setTimeout(()=>{// // window?.euu1 = availablePools// // window?.euu2 = availablePools.size// console.log(availablePools.size)// }, 8000)let pivotNode = pivotNodes.get(availablePool);if (!pivotNode) pivotNodes.set(availablePool, pivotNode = availablePool.head) // cached the previous newest node (head) as pivotNodeavailablePool.insertBeforeNode(pivotNode, entryRecord); // head = newest, tail = oldest}}}noTimeCheck = false;}const attachedDefine = function () {Promise.resolve().then(timeCheck);try {const hostElement = this?.hostElement;if (hostElement instanceof HTMLElement) {const entryRecord = entryRecords.get(hostElement);if (entryRecord && entryRecord[0].deref() === hostElement && hostElement.isConnected === true && this?.isAttached === true) {noTimeCheck = true;const ct = Date.now();entryRecord[1] = ct;entryRecord[2] = -1;entryRecord[3] = ct;operations.delete(entryRecord);operations.add(entryRecord);noTimeCheck = false;// note: because of performance prespective, deletion for availablePools[eKey]'s linked element would not be done here.// entryRecord[4] is not required to be updated here.}}} catch (e) { }return this.attached9512();}const detachedDefine = function () {Promise.resolve().then(timeCheck);try {const hostElement = this?.hostElement;if (hostElement instanceof HTMLElement) {const entryRecord = entryRecords.get(hostElement);if (entryRecord && entryRecord[0].deref() === hostElement && hostElement.isConnected === false && this?.isAttached === false) {noTimeCheck= true;const ct = Date.now();entryRecord[2] = ct;entryRecord[1] = -1;entryRecord[3] = ct;operations.delete(entryRecord);operations.add(entryRecord);noTimeCheck= false;// note: because of performance prespective, deletion for availablePools[eKey]'s linked element would not be done here.// entryRecord[4] is not required to be updated here.}}} catch (e) { }return this.detached9512();}// function cpy(x) {// if (!x) return x;// try {// if (typeof x === 'object' && typeof x.length ==='number' && typeof x.slice === 'function') {// x = x.slice(0)// } else if (typeof x === 'object' && !x.length) {// x = JSON.parse(JSON.stringify(x));// } else {// return Object.assign({}, x);// }// } catch (e) { }// return x;// }async function digestMessage(message) {const msgUint8 = new TextEncoder().encode(message); // (utf-8 の) Uint8Array にエンコードするconst hashBuffer = await crypto.subtle.digest("SHA-256", msgUint8); // メッセージをハッシュするconst hashArray = Array.from(new Uint8Array(hashBuffer)); // バッファーをバイト列に変換するconst hashHex = hashArray.map((b) => b.toString(16).padStart(2, "0")).join(""); // バイト列を 16 進文字列に変換するreturn hashHex.toUpperCase();}let onPageContainer = null;const createComponentDefine_ = function (a, b, c) {Promise.resolve().then(timeCheck);const creatorTag = this?.is || this?.nodeName?.toLowerCase() || '';const componentTag = typeof a === 'string' ? a : ((a || 0).component || '');const eKey = creatorTag && componentTag ? `${creatorTag}.${componentTag}` : '*'; // '*' for play-safeconst availablePool = availablePools.get(eKey);try {if (availablePool instanceof LinkedArray) {noTimeCheck = true;let node = availablePool.tail; // oldestwhile (node instanceof LinkedArray.Node) {const entryRecord = node.value;const prevNode = node.prev;let ok = false;let elm = null;if (entryRecord[1] < 0 && entryRecord[2] > 0 && entryRecord[4]) {elm = entryRecord[0].deref();// elm && console.log(3882, (elm.__shady_native_textContent || elm.textContent))if (elm && elm instanceof HTMLElement && elm.isConnected === false && insp(elm).isAttached === false && elm.parentNode === null) {ok = true;}}if (ok) {// useEntryRecord = entryRecord;entryRecord[4] = false;// console.log('nodeDeleted', 1, entryRecord[0].deref().nodeName)availablePool.deleteNode(node);// break;if (!onPageContainer) {let p = document.createElement('noscript');document.body.prepend(p);onPageContainer = p;}onPageContainer.appendChild(elm); // to fix some issues for the rendered elementsconst cnt = insp(elm);cnt.__dataInvalid = false;// cnt._initializeProtoProperties(cnt.data)// window.meaa = cnt.$.container;if (typeof (cnt.__data || 0) === 'object') {cnt.__data = Object.assign({}, cnt.__data);}cnt.__dataPending = {};cnt.__dataOld = {};try {cnt.markDirty();} catch (e) { }try {cnt.markDirtyVisibilityObserver();} catch (e) { }try{cnt.wasPrescan = cnt.wasVisible = !1}catch(e){}// try{// cnt._setPendingProperty('data', Object.assign({}, cntData), !0);// }catch(e){}// try {// cnt._flushProperties();// } catch (e) { }if (DEBUG_OPT && DEBUG_dataChangeReflection) {let jC1 = null;let jC2 = null;const jKey = `${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`;try {jC1 = (cnt.hostElement.__shady_native_textContent || cnt.hostElement.textContent);// console.log(83802, jKey, (cnt.hostElement.__shady_native_textContent || cnt.hostElement.textContent))} catch (e) {console.warn(e);}setTimeout(() => {try {jC2 = (cnt.hostElement.__shady_native_textContent || cnt.hostElement.textContent);// console.log(83804, jKey, (cnt.hostElement.__shady_native_textContent || cnt.hostElement.textContent))} catch (e) {console.warn(e);}(async () => {jC1 = await digestMessage(jC1);jC2 = await digestMessage(jC2);console.log(83804, jKey, jC1.substring(0, 7), jC2.substring(0, 7))})()}, 1000);}// // try{// // console.log(83801, JSON.stringify(cntData))// // }catch(e){// // console.warn(e);// // }// const jKey = `${Math.floor(Math.random() * 314159265359 + 314159265359).toString(36)}`;// try{// console.log(83802, jKey, (cnt.hostElement.__shady_native_textContent || cnt.hostElement.textContent))// }catch(e){// console.warn(e);// }// setTimeout(()=>{// // try{// // console.log(83803, JSON.stringify(cntData))// // }catch(e){// // console.warn(e);// // }// try{// console.log(83804, jKey, (cnt.hostElement.__shady_native_textContent || cnt.hostElement.textContent))// }catch(e){// console.warn(e);// }// }, 1000);// reference// https://www.youtube.com/s/desktop/c01ea7e3/jsbin/live_chat_polymer.vflset/live_chat_polymer.js// a.prototype._initializeProtoProperties = function(c) {// this.__data = Object.create(c);// this.__dataPending = Object.create(c);// this.__dataOld = {}// }// ------- (NO USE) ------//// a.prototype._initializeProperties = function() {// this.__dataProto && (this._initializeProtoProperties(this.__dataProto),// this.__dataProto = null);// b.prototype._initializeProperties.call(this)// }// ;// a.prototype._initializeProtoProperties = function(c) {// for (var d in c)// this._setProperty(d, c[d])// }//// ------- (NO USE) ------// // cnt.__dataReady = false;// cnt.__dataInvalid = true;// cnt.__dataEnabled = false; // tbc// // if('__dataEnabled' in cnt) cnt.__dataEnabled = false;// // if ('__dataReady' in cnt && typeof cnt.__dataReady === 'boolean') cnt.__dataReady = false;// // if ('__dataInvalid' in cnt && typeof cnt.__dataInvalid === 'boolean') cnt.__dataInvalid = true;// // try {// // if ('data' in cnt) cnt.data = null;// // if ('__data' in cnt) cnt.__data = null;// // } catch (e) {// // console.warn(e)// // }// // try {// // if ('data' in cnt) cnt.data = {};// // if ('__data' in cnt) cnt.__data = {};// // } catch (e) {// // console.warn(e)// // }// // const noValue = noValues.get(eKey);// // if(noValue){// // if(!noValue.data) cnt.data = noValue.data;// // if(!noValue.__data) cnt.data = noValue.__data;// // }// // const defaultValue = defaultValues.get(eKey);// // if (defaultValue) {// // try {// // if ('data' in defaultValue) cnt.data = cpy(cnt.data);// // if ('__data' in defaultValue) cnt.__data = cpy(cnt.__data);// // } catch (e) {// // console.warn(e)// // }// // }// // const flg001 = elm.__rm3Flg001__;// // if (cnt.__dataEnabled !== flg001) cnt.__dataEnabled = flg001;// // const flg001 = elm.__rm3Flg001__;// // if (cnt.__dataEnabled !== flg001) cnt.__dataEnabled = flg001;// if (cnt.__dataPending && typeof cnt.__dataPending === 'object') cnt.__dataPending = null;// if (cnt.__dataOld && typeof cnt.__dataOld === 'object') cnt.__dataOld = null;// // cnt.__dataInstanceProps = null;// if (cnt.__dataCounter && typeof cnt.__dataCounter === 'number') cnt.__dataCounter = 0;// // cnt.__serializing = !1;// if ('__dataClientsInitialized' in cnt || '__dataClientsReady' in cnt) {// if ('__dataClientsInitialized' in cnt !== '__dataClientsReady' in cnt) {// console.log('[rm3-warning] __dataClientsInitialized and __dataClientsReady should exist in the controller');// }// cnt.__dataClientsReady = !1;// cnt.__dataLinkedPaths = cnt.__dataToNotify = cnt.__dataPendingClients = null;// cnt.__dataHasPaths = !1;// cnt.__dataCompoundStorage = null; // cnt.__dataCompoundStorage = cnt.__dataCompoundStorage || null;// cnt.__dataHost = null; // cnt.__dataHost = cnt.__dataHost || null;// if (!cnt.__dataTemp) cnt.__dataTemp = {}; // cnt.__dataTemp = {};// cnt.__dataClientsInitialized = !1;// }if (entryRecord[5] < 1e9) entryRecord[5] += 1;DEBUG_OPT && Promise.resolve().then(() => console.log(`${eKey} reuse`, entryRecord)); // give some time for attach processDEBUG_OPT && reuseRecord_.add([Date.now(), cnt.is, entryRecord]);DEBUG_OPT && reuseCount_.set(cnt.is, (reuseCount_.get(cnt.is) || 0) + 1)if (rm3.reuseCount < 1e9) rm3.reuseCount++;return elm;}// console.log('condi88', entryRecord[1] < 0 , entryRecord[2] > 0 , !!entryRecord[4], !!entryRecord[0].deref())entryRecord[4] = false;// console.log(entryRecord);// console.log('nodeDeleted',2, entryRecord[0]?.deref()?.nodeName)availablePool.deleteNode(node);node = prevNode;}// for(const ) availablePool// noTimeCheck = false;}} catch (e) {console.warn(e)}noTimeCheck = false;// console.log('createComponentDefine_', a, b, c)// if (!reusePool.has(componentTag)) reusePool.set(componentTag, new LinkedArray()); // xx858// const pool = reusePool.get(componentTag); // xx858// if (!(pool instanceof LinkedArray)) throw new Error(); // xx858const newElement = this.createComponent9512_(a, b, c);// if(componentTag.indexOf( 'ticker')>=0)console.log(1883, a,newElement)try {const cntE = insp(newElement);if (!cntE.attached9512 && cntE.attached) {const cProtoE = getProto(newElement);if (cProtoE.attached === cntE.attached) {if (!cProtoE.attached9512 && typeof cProtoE.attached === 'function' && cProtoE.attached.length === 0) {cProtoE.attached9512 = cProtoE.attached;cProtoE.attached = attachedDefine;// hookTos.add(a);}} else {if (typeof cntE.attached === 'function' && cntE.attached.length === 3) {cntE.attached9512 = cntE.attached;cntE.attached = attachedDefine;// hookTos.add(a);}}}if (!cntE.detached9512 && cntE.detached) {const cProtoE = getProto(newElement);if (cProtoE.detached === cntE.detached) {if (!cProtoE.detached9512 && typeof cProtoE.detached === 'function' && cProtoE.detached.length === 0) {cProtoE.detached9512 = cProtoE.detached;cProtoE.detached = detachedDefine;// hookTos.add(a);}} else {if (typeof cntE.detached === 'function' && cntE.detached.length === 3) {cntE.detached9512 = cntE.detached;cntE.detached = detachedDefine;// hookTos.add(a);}}}const acceptance = true;// const acceptance = !cntE.__dataReady && cntE.__dataInvalid !== false; // we might need to change the acceptance condition along with YouTube Coding updates.if (acceptance) {// [[ weak ElementNode, attached time, detached time, time of change, inside availablePool, reuse count ]]const entryRecord = [new WeakRef(newElement), -1, -1, -1, false, 0];newElement.__rm3Tag003__ = eKey;// pool.push(entryRecord);entryRecords.set(newElement, entryRecord);// newElement.__rm3Tag001__ = creatorTag;// newElement.__rm3Tag002__ = componentTag;// newElement.__rm3Flg001__ = cntE.__dataEnabled;// // console.log(5928, cntE.data, cntE.__data)// if (!defaultValues.has(eKey)){// const o = {};// if('data' in cntE) o.data = cpy(cntE.data);// if('__data' in cntE) o.__data = cpy(cntE.__data);// defaultValues.set(eKey, o);// }// if(!noValues.has(eKey)){// const o = {};// o.data = true;// try {// if (!cntE.data) o.data = cntE.data;// } catch (e) { }// o.__data = true;// try {// if (!cntE.__data) o.__data = cntE.__data;// } catch (e) { }// noValues.set(eKey, o)// }} else {// console.log(5920, cntE.__dataReady, cntE.__dataInvalid)}} catch (e) {console.warn(e);}return newElement;}document.createElement9512 = document.createElement;document.createElement = function (a) {const r = document.createElement9512(a);try {const cnt = insp(r);if (cnt.createComponent_ && !cnt.createComponent9512_) {const cProto = getProto(r);if (cProto.createComponent_ === cnt.createComponent_) {if (!cProto.createComponent9512_ && typeof cProto.createComponent_ === 'function' && cProto.createComponent_.length === 3) {cProto.createComponent9512_ = cProto.createComponent_;cProto.createComponent_ = createComponentDefine_;DEBUG_OPT && hookTos.add(a);}} else {if (typeof cnt.createComponent_ === 'function' && cnt.createComponent_.length === 3) {cnt.createComponent9512_ = cnt.createComponent_;cnt.createComponent_ = createComponentDefine_;DEBUG_OPT && hookTos.add(a);}}}} catch (e) {console.warn(e)}return r;}rm3.checkWhetherUnderParent = () => {const r = [];for (const operation of operations) {const elm = operation[0].deref();if (operation[2] > 0) {r.push([!!elm, elm?.nodeName.toLowerCase(), elm?.parentNode === null]);}}return r;}rm3.hookTags = () => {const r = new Set();for (const operation of operations) {const elm = operation[0].deref();if (elm && elm.is) {r.add(elm.is)}}return [...r];}DEBUG_OPT && (rm3.reuseRecord = () => {return [...reuseRecord_]; // [[debug]]});DEBUG_OPT && (rm3.reuseCount_ = reuseCount_);}(rm3.reuseCount = 0); // window.rm3 will be zero initially if this script has no runtime complier error in the initialization phase.})();