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.

2024-12-21 يوللانغان نەشرى. ئەڭ يېڭى نەشرىنى كۆرۈش.

  1. // ==UserScript==
  2. // @name YouTube RM3 - Reduce Memory Usage by Reusing Components
  3. // @namespace Violentmonkey Scripts
  4. // @match https://www.youtube.com/*
  5. // @match https://studio.youtube.com/live_chat*
  6. //
  7. // @version 0.1.0003
  8. //
  9. // @author CY Fung
  10. // @run-at document-start
  11. // @grant none
  12. // @unwrap
  13. // @allFrames true
  14. // @inject-into page
  15. //
  16. // @compatible firefox Violentmonkey
  17. // @compatible firefox Tampermonkey
  18. // @compatible firefox FireMonkey
  19. // @compatible chrome Violentmonkey
  20. // @compatible chrome Tampermonkey
  21. // @compatible opera Violentmonkey
  22. // @compatible opera Tampermonkey
  23. // @compatible safari Stay
  24. // @compatible edge Violentmonkey
  25. // @compatible edge Tampermonkey
  26. // @compatible brave Violentmonkey
  27. // @compatible brave Tampermonkey
  28. //
  29. // @description A simple tool that runs in the background to reuse YouTube components, thereby reducing memory usage over time.
  30. // @description:en A simple tool that runs in the background to reuse YouTube components, thereby reducing memory usage over time.
  31. // @description:ja YouTubeコンポーネントを再利用することで、長期的なメモリ使用量の削減を目指す、バックグラウンドで実行されるシンプルなツールです。
  32. // @description:zh-TW 一個在背景執行的簡易工具,可重複利用 YouTube 元件,從而在長期減少記憶體使用量。
  33. // @description:zh-CN 一个在后台运行的简单工具,通过重复利用 YouTube 组件,从而在长期减少内存使用量。
  34. //
  35. // ==/UserScript==
  36.  
  37. const rm3 = window.rm3 = {};
  38. // console.log(3001);
  39.  
  40. (() => {
  41.  
  42. const DEBUG_OPT = false;
  43. const CONFIRM_TIME = 4000;
  44. const CHECK_INTERVAL = 400;
  45.  
  46.  
  47. /** @type {globalThis.PromiseConstructor} */
  48. const Promise = (async () => { })().constructor; // YouTube hacks Promise in WaterFox Classic and "Promise.resolve(0)" nevers resolve.
  49.  
  50. // https://qiita.com/piroor/items/02885998c9f76f45bfa0
  51. // https://gist.github.com/piroor/829ecb32a52c2a42e5393bbeebe5e63f
  52. function uniq(array) {
  53. return [...new Set(array)];
  54. };
  55.  
  56.  
  57. rm3.uniq = uniq; // [[debug]]
  58.  
  59.  
  60. rm3.inspect = () => {
  61. return uniq([...document.getElementsByTagName('*')].filter(e => e?.polymerController?.createComponent_).map(e => e.nodeName)); // [[debug]]
  62. }
  63.  
  64.  
  65. const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0);
  66. const indr = o => insp(o).$ || o.$ || 0;
  67.  
  68. const getProto = (element) => {
  69. if (element) {
  70. const cnt = insp(element);
  71. return cnt.constructor.prototype || null;
  72. }
  73. return null;
  74. }
  75.  
  76.  
  77. const LinkedArray = (() => {
  78.  
  79.  
  80. class Node {
  81. constructor(value) {
  82. this.value = value;
  83. this.next = null;
  84. this.prev = null;
  85. }
  86. }
  87.  
  88. class LinkedArray {
  89. constructor() {
  90. this.head = null;
  91. this.tail = null;
  92. this.length = 0;
  93. }
  94.  
  95. push(value) {
  96. const newNode = new Node(value);
  97. if (this.length === 0) {
  98. this.head = newNode;
  99. this.tail = newNode;
  100. } else {
  101. this.tail.next = newNode;
  102. newNode.prev = this.tail;
  103. this.tail = newNode;
  104. }
  105. this.length++;
  106. return this.length;
  107. }
  108.  
  109. pop() {
  110. if (this.length === 0) return undefined;
  111. const removedNode = this.tail;
  112. if (this.length === 1) {
  113. this.head = null;
  114. this.tail = null;
  115. } else {
  116. this.tail = removedNode.prev;
  117. this.tail.next = null;
  118. removedNode.prev = null;
  119. }
  120. this.length--;
  121. return removedNode.value;
  122. }
  123.  
  124. unshift(value) {
  125. const newNode = new Node(value);
  126. if (this.length === 0) {
  127. this.head = newNode;
  128. this.tail = newNode;
  129. } else {
  130. newNode.next = this.head;
  131. this.head.prev = newNode;
  132. this.head = newNode;
  133. }
  134. this.length++;
  135. return this.length;
  136. }
  137.  
  138. shift() {
  139. if (this.length === 0) return undefined;
  140. const removedNode = this.head;
  141. if (this.length === 1) {
  142. this.head = null;
  143. this.tail = null;
  144. } else {
  145. this.head = removedNode.next;
  146. this.head.prev = null;
  147. removedNode.next = null;
  148. }
  149. this.length--;
  150. return removedNode.value;
  151. }
  152.  
  153. size() {
  154. return this.length;
  155. }
  156.  
  157. // Get a node by index (0-based)
  158. getNode(index) {
  159. if (index < 0 || index >= this.length) return null;
  160.  
  161. let current;
  162. let counter;
  163.  
  164. // Optimization: start from closest end
  165. if (index < this.length / 2) {
  166. current = this.head;
  167. counter = 0;
  168. while (counter !== index) {
  169. current = current.next;
  170. counter++;
  171. }
  172. } else {
  173. current = this.tail;
  174. counter = this.length - 1;
  175. while (counter !== index) {
  176. current = current.prev;
  177. counter--;
  178. }
  179. }
  180. return current;
  181. }
  182.  
  183. // Get value by index
  184. get(index) {
  185. const node = this.getNode(index);
  186. return node ? node.value : undefined;
  187. }
  188.  
  189. // Find the first node with the given value and return both node and index
  190. findNode(value) {
  191. let current = this.head;
  192. let idx = 0;
  193. while (current) {
  194. if (current.value === value) {
  195. return { node: current, index: idx };
  196. }
  197. current = current.next;
  198. idx++;
  199. }
  200. return { node: null, index: -1 };
  201. }
  202.  
  203. toArray() {
  204. const arr = [];
  205. let current = this.head;
  206. while (current) {
  207. arr.push(current.value);
  208. current = current.next;
  209. }
  210. return arr;
  211. }
  212.  
  213. // Insert a new value before a given node (provided you already have the node reference)
  214. insertBeforeNode(node, newValue) {
  215. if (!node) {
  216. this.unshift(newValue);
  217. return true;
  218. }
  219.  
  220. if (node === this.head) {
  221. // If the target is the head, just unshift
  222. this.unshift(newValue);
  223. } else {
  224. const newNode = new Node(newValue);
  225. const prevNode = node.prev;
  226.  
  227. prevNode.next = newNode;
  228. newNode.prev = prevNode;
  229. newNode.next = node;
  230. node.prev = newNode;
  231.  
  232. this.length++;
  233. }
  234. return true;
  235. }
  236.  
  237. // Insert a new value after a given node (provided you already have the node reference)
  238. insertAfterNode(node, newValue) {
  239.  
  240. if (!node) {
  241. this.push(newValue);
  242. return true;
  243. }
  244.  
  245. if (node === this.tail) {
  246. // If the target is the tail, just push
  247. this.push(newValue);
  248. } else {
  249. const newNode = new Node(newValue);
  250. const nextNode = node.next;
  251.  
  252. node.next = newNode;
  253. newNode.prev = node;
  254. newNode.next = nextNode;
  255. nextNode.prev = newNode;
  256.  
  257. this.length++;
  258. }
  259. return true;
  260. }
  261.  
  262. // Insert a new value before the first occurrence of an existing value (search by value)
  263. insertBefore(existingValue, newValue) {
  264. const { node } = this.findNode(existingValue);
  265. if (!node) return false; // Not found
  266. return this.insertBeforeNode(node, newValue);
  267. }
  268.  
  269. // Insert a new value after the first occurrence of an existing value (search by value)
  270. insertAfter(existingValue, newValue) {
  271. const { node } = this.findNode(existingValue);
  272. if (!node) return false; // Not found
  273. return this.insertAfterNode(node, newValue);
  274. }
  275.  
  276.  
  277.  
  278. // Delete a given node from the list
  279. deleteNode(node) {
  280. if (!node) return false;
  281.  
  282. if (this.length === 1 && node === this.head && node === this.tail) {
  283. // Only one element in the list
  284. this.head = null;
  285. this.tail = null;
  286. } else if (node === this.head) {
  287. // Node is the head
  288. this.head = node.next;
  289. this.head.prev = null;
  290. node.next = null;
  291. } else if (node === this.tail) {
  292. // Node is the tail
  293. this.tail = node.prev;
  294. this.tail.next = null;
  295. node.prev = null;
  296. } else {
  297. // Node is in the middle
  298. const prevNode = node.prev;
  299. const nextNode = node.next;
  300. prevNode.next = nextNode;
  301. nextNode.prev = prevNode;
  302. node.prev = null;
  303. node.next = null;
  304. }
  305.  
  306. this.length--;
  307. return true;
  308. }
  309.  
  310. }
  311.  
  312.  
  313. LinkedArray.Node = Node;
  314. return LinkedArray;
  315. })();
  316.  
  317.  
  318.  
  319. class LimitedSizeSet extends Set {
  320. constructor(n) {
  321. super();
  322. this.limit = n;
  323. }
  324.  
  325. add(key) {
  326. if (!super.has(key)) {
  327. super.add(key);
  328. let n = super.size - this.limit;
  329. if (n > 0) {
  330. const iterator = super.values();
  331. do {
  332. const firstKey = iterator.next().value; // Get the first (oldest) key
  333. super.delete(firstKey); // Delete the oldest key
  334. } while (--n > 0)
  335. }
  336. }
  337. }
  338.  
  339. removeAdd(key) {
  340. super.delete(key);
  341. this.add(key);
  342. }
  343.  
  344. }
  345.  
  346.  
  347.  
  348. if (!document.createElement9512 && typeof document.createElement === 'function' && document.createElement.length === 1) {
  349.  
  350. // sizing of Map / Set. Shall limit ?
  351.  
  352. const hookTos = new Set(); // [[debug]]
  353. DEBUG_OPT && (rm3.hookTos = hookTos);
  354.  
  355. // const reusePool = new Map(); // xx858
  356. const entryRecords = new WeakMap(); // a weak link between element and record
  357.  
  358. // rm3.list = [];
  359.  
  360. const operations = rm3.operations = new Set(); // to find out the "oldest elements"
  361.  
  362. const availablePools = rm3.availablePools = new Map(); // those "old elements" can be used
  363. let lastTimeCheck = 0;
  364.  
  365. const reuseRecord_ = new LimitedSizeSet(256); // [[debug]]
  366.  
  367. DEBUG_OPT && (rm3.reuseRecord = () => {
  368. return [...reuseRecord_]; // [[debug]]
  369. });
  370.  
  371. // const defaultValues = new Map();
  372. // const noValues = new Map();
  373.  
  374. const timeCheck = () => {
  375. // regularly check elements are old enough to put into the available pools
  376. // 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.
  377.  
  378. const ct = Date.now();
  379. if (ct - lastTimeCheck < CHECK_INTERVAL) return;
  380. lastTimeCheck = ct;
  381.  
  382. // 16,777,216
  383. if (hookTos.size > 777216) hookTos.clear(); // just debug usage, dont concern
  384. if (operations.size > 7777216) {
  385. // extremely old elements in operations mean they have no attach/detach action. so no reuse as well. they are just trash in memory.
  386. // as no checking of the weakRef.deref() being null or not, those trash could be already cleaned. However we don't concern this.
  387. // (not to count whether they are actual memory trash or not)
  388. const half = operations.size >>> 1;
  389. let i = 0;
  390. for (const value of operations) {
  391. if (i++ > half) {
  392. operations.delete(value);
  393. }
  394. }
  395. }
  396.  
  397. const iterator = operations[Symbol.iterator]();
  398.  
  399. const targetTime = ct - CONFIRM_TIME;
  400. let iteratorResult;
  401.  
  402. while (true) {
  403. iteratorResult = iterator.next(); // 順番に値を取りだす
  404. if (iteratorResult.done) break; // 取り出し終えたなら、break
  405. if (iteratorResult.value[3] > targetTime) continue;
  406. break;
  407. }
  408.  
  409. let pivotNodes = new WeakMap();
  410. while (!iteratorResult.done) {
  411. const entryRecord = iteratorResult.value;
  412. if (entryRecord[1] < 0 && entryRecord[2] > 0 && !entryRecord[4]) {
  413. const element = entryRecord[0].deref();
  414. if (element instanceof HTMLElement && element.isConnected === false && insp(element).isAttached === false) {
  415. entryRecord[4] = true;
  416. const creatorTag = element.__rm3Tag001__;
  417. const componentTag = element.__rm3Tag002__;
  418. const eKey = creatorTag && componentTag ? `${creatorTag}.${componentTag}` : '*'; // '*' for play-safe
  419. let availablePool = availablePools.get(eKey);
  420. if (!availablePool) availablePools.set(eKey, availablePool = new LinkedArray());
  421. if (!(availablePool instanceof LinkedArray)) throw new Error();
  422. let pivotNode = pivotNodes.get(availablePool);
  423. if (!pivotNode) pivotNodes.set(availablePool, pivotNode = availablePool.head) // cached the previous newest node (head) as pivotNode
  424.  
  425. availablePool.insertBeforeNode(pivotNode, entryRecord); // head = newest, tail = oldest
  426. }
  427. }
  428. iteratorResult = iterator.next();
  429. }
  430.  
  431. }
  432.  
  433. const attachedDefine = function () {
  434.  
  435. Promise.resolve().then(timeCheck);
  436. try {
  437. const hostElement = this?.hostElement;
  438. if (hostElement instanceof HTMLElement) {
  439. const entryRecord = entryRecords.get(hostElement);
  440. if (entryRecord && entryRecord[0].deref() === hostElement && hostElement.isConnected === true && this?.isAttached === true) {
  441. const ct = Date.now();
  442. entryRecord[1] = ct;
  443. entryRecord[2] = -1;
  444. entryRecord[3] = ct;
  445. operations.delete(entryRecord);
  446. operations.add(entryRecord);
  447. // note: because of performance prespective, deletion for availablePools[eKey]'s linked element would not be done here.
  448. // entryRecord[4] is not required to be updated here.
  449. }
  450. }
  451. } catch (e) { }
  452. return this.attached9512();
  453. }
  454. const detachedDefine = function () {
  455.  
  456. Promise.resolve().then(timeCheck);
  457. try {
  458. const hostElement = this?.hostElement;
  459. if (hostElement instanceof HTMLElement) {
  460. const entryRecord = entryRecords.get(hostElement);
  461. if (entryRecord && entryRecord[0].deref() === hostElement && hostElement.isConnected === false && this?.isAttached === false) {
  462. const ct = Date.now();
  463. entryRecord[2] = ct;
  464. entryRecord[1] = -1;
  465. entryRecord[3] = ct;
  466. operations.delete(entryRecord);
  467. operations.add(entryRecord);
  468. // note: because of performance prespective, deletion for availablePools[eKey]'s linked element would not be done here.
  469. // entryRecord[4] is not required to be updated here.
  470. }
  471. }
  472. } catch (e) { }
  473.  
  474. return this.detached9512();
  475. }
  476.  
  477.  
  478. // function cpy(x) {
  479. // if (!x) return x;
  480. // try {
  481. // if (typeof x === 'object' && typeof x.length ==='number' && typeof x.slice === 'function') {
  482. // x = x.slice(0)
  483. // } else if (typeof x === 'object' && !x.length) {
  484. // x = JSON.parse(JSON.stringify(x));
  485. // } else {
  486. // return Object.assign({}, x);
  487. // }
  488. // } catch (e) { }
  489. // return x;
  490. // }
  491.  
  492.  
  493. const createComponentDefine_ = function (a, b, c) {
  494.  
  495. Promise.resolve().then(timeCheck);
  496.  
  497.  
  498. const creatorTag = this?.is || this?.nodeName?.toLowerCase() || '';
  499.  
  500. const componentTag = typeof a === 'string' ? a : ((a || 0).component || '');
  501.  
  502.  
  503.  
  504. const eKey = creatorTag && componentTag ? `${creatorTag}.${componentTag}` : '*'; // '*' for play-safe
  505. const availablePool = availablePools.get(eKey);
  506.  
  507. try {
  508.  
  509. if (availablePool instanceof LinkedArray) {
  510.  
  511. let node = availablePool.tail; // oldest
  512.  
  513. while (node instanceof LinkedArray.Node) {
  514. const entryRecord = node.value;
  515. const prevNode = node.prev;
  516.  
  517. let ok = true;
  518. let elm = null;
  519. if (entryRecord[1] > 0 || entryRecord[2] < 0 || !entryRecord[4]) {
  520. ok = false;
  521. } else {
  522. elm = entryRecord[0].deref();
  523.  
  524. if (!elm) ok = false;
  525. else {
  526.  
  527. if (elm instanceof HTMLElement && elm.isConnected === false && insp(elm).isAttached === false) {
  528.  
  529. ok = true;
  530. }
  531. }
  532.  
  533.  
  534. }
  535.  
  536. if (ok) {
  537.  
  538. // useEntryRecord = entryRecord;
  539. entryRecord[4] = false;
  540. availablePool.deleteNode(node);
  541. // break;
  542.  
  543.  
  544. const cnt = insp(elm);
  545.  
  546. // cnt.__dataReady = false;
  547. cnt.__dataInvalid = true;
  548. cnt.__dataEnabled = false; // tbc
  549. // if('__dataEnabled' in cnt) cnt.__dataEnabled = false;
  550. // if ('__dataReady' in cnt && typeof cnt.__dataReady === 'boolean') cnt.__dataReady = false;
  551. // if ('__dataInvalid' in cnt && typeof cnt.__dataInvalid === 'boolean') cnt.__dataInvalid = true;
  552.  
  553. // try {
  554. // if ('data' in cnt) cnt.data = null;
  555. // if ('__data' in cnt) cnt.__data = null;
  556. // } catch (e) {
  557. // console.warn(e)
  558. // }
  559.  
  560. // try {
  561. // if ('data' in cnt) cnt.data = {};
  562. // if ('__data' in cnt) cnt.__data = {};
  563. // } catch (e) {
  564. // console.warn(e)
  565. // }
  566.  
  567.  
  568.  
  569.  
  570.  
  571.  
  572.  
  573.  
  574.  
  575.  
  576.  
  577. // const noValue = noValues.get(eKey);
  578. // if(noValue){
  579. // if(!noValue.data) cnt.data = noValue.data;
  580. // if(!noValue.__data) cnt.data = noValue.__data;
  581. // }
  582.  
  583. // const defaultValue = defaultValues.get(eKey);
  584. // if (defaultValue) {
  585.  
  586. // try {
  587. // if ('data' in defaultValue) cnt.data = cpy(cnt.data);
  588. // if ('__data' in defaultValue) cnt.__data = cpy(cnt.__data);
  589. // } catch (e) {
  590. // console.warn(e)
  591. // }
  592. // }
  593.  
  594. // const flg001 = elm.__rm3Flg001__;
  595. // if (cnt.__dataEnabled !== flg001) cnt.__dataEnabled = flg001;
  596.  
  597.  
  598.  
  599.  
  600.  
  601.  
  602.  
  603. // const flg001 = elm.__rm3Flg001__;
  604. // if (cnt.__dataEnabled !== flg001) cnt.__dataEnabled = flg001;
  605.  
  606.  
  607. if (cnt.__dataPending && typeof cnt.__dataPending === 'object') cnt.__dataPending = null;
  608. if (cnt.__dataOld && typeof cnt.__dataOld === 'object') cnt.__dataOld = null;
  609.  
  610. // cnt.__dataInstanceProps = null;
  611. if (cnt.__dataCounter && typeof cnt.__dataCounter === 'number') cnt.__dataCounter = 0;
  612. // cnt.__serializing = !1;
  613.  
  614.  
  615.  
  616. if ('__dataClientsInitialized' in cnt || '__dataClientsReady' in cnt) {
  617.  
  618. if ('__dataClientsInitialized' in cnt !== '__dataClientsReady' in cnt) {
  619.  
  620. console.log('[rm3-warning] __dataClientsInitialized and __dataClientsReady should exist in the controller');
  621.  
  622. }
  623.  
  624. cnt.__dataClientsReady = !1;
  625. cnt.__dataLinkedPaths = cnt.__dataToNotify = cnt.__dataPendingClients = null;
  626. cnt.__dataHasPaths = !1;
  627. cnt.__dataCompoundStorage = null; // cnt.__dataCompoundStorage = cnt.__dataCompoundStorage || null;
  628. cnt.__dataHost = null; // cnt.__dataHost = cnt.__dataHost || null;
  629. if (!cnt.__dataTemp) cnt.__dataTemp = {}; // cnt.__dataTemp = {};
  630. cnt.__dataClientsInitialized = !1;
  631.  
  632. }
  633.  
  634. if (entryRecord[5] < 1e9) entryRecord[5] += 1;
  635. DEBUG_OPT && Promise.resolve().then(() => console.log(`${eKey} reuse`, entryRecord)); // give some time for attach process
  636. DEBUG_OPT && reuseRecord_.add([Date.now(), entryRecord]);
  637. if (rm3.reuseCount < 1e9) rm3.reuseCount++;
  638.  
  639. return elm;
  640.  
  641.  
  642. }
  643.  
  644. entryRecord[4] = false;
  645. availablePool.deleteNode(node);
  646. node = prevNode;
  647.  
  648. }
  649. // for(const ) availablePool
  650. }
  651.  
  652. } catch (e) {
  653. console.warn(e)
  654. }
  655.  
  656.  
  657. // console.log('createComponentDefine_', a, b, c)
  658.  
  659. // if (!reusePool.has(componentTag)) reusePool.set(componentTag, new LinkedArray()); // xx858
  660.  
  661. // const pool = reusePool.get(componentTag); // xx858
  662. // if (!(pool instanceof LinkedArray)) throw new Error(); // xx858
  663.  
  664.  
  665. const newElement = this.createComponent9512_(a, b, c);
  666. // if(componentTag.indexOf( 'ticker')>=0)console.log(1883, a,newElement)
  667.  
  668. try {
  669.  
  670. const cntE = insp(newElement);
  671. if (cntE.attached && !cntE.attached9512) {
  672.  
  673. const cProtoE = getProto(newElement);
  674.  
  675.  
  676. if (cProtoE.attached === cntE.attached) {
  677.  
  678. if (!cProtoE.attached9512 && typeof cProtoE.attached === 'function' && cProtoE.attached.length === 0) {
  679.  
  680. cProtoE.attached9512 = cProtoE.attached;
  681.  
  682. cProtoE.attached = attachedDefine;
  683. // hookTos.add(a);
  684. }
  685. } else {
  686.  
  687. if (typeof cntE.attached === 'function' && cntE.attached.length === 3) {
  688. cntE.attached9512 = cntE.attached;
  689.  
  690. cntE.attached = attachedDefine;
  691. // hookTos.add(a);
  692. }
  693. }
  694.  
  695.  
  696. }
  697.  
  698. if (cntE.detached && !cntE.detached9512) {
  699.  
  700. const cProtoE = getProto(newElement);
  701.  
  702.  
  703. if (cProtoE.detached === cntE.detached) {
  704.  
  705. if (!cProtoE.detached9512 && typeof cProtoE.detached === 'function' && cProtoE.detached.length === 0) {
  706.  
  707. cProtoE.detached9512 = cProtoE.detached;
  708.  
  709. cProtoE.detached = detachedDefine;
  710. // hookTos.add(a);
  711. }
  712. } else {
  713.  
  714. if (typeof cntE.detached === 'function' && cntE.detached.length === 3) {
  715. cntE.detached9512 = cntE.detached;
  716.  
  717. cntE.detached = detachedDefine;
  718. // hookTos.add(a);
  719. }
  720. }
  721.  
  722.  
  723. }
  724.  
  725.  
  726. const acceptance = true;
  727. // const acceptance = !cntE.__dataReady && cntE.__dataInvalid !== false; // we might need to change the acceptance condition along with YouTube Coding updates.
  728. if (acceptance) {
  729.  
  730. // [[ weak ElementNode, attached time, detached time, time of change, inside availablePool, reuse count ]]
  731. const entryRecord = [new WeakRef(newElement), -1, -1, -1, false, 0];
  732.  
  733. // pool.push(entryRecord);
  734. entryRecords.set(newElement, entryRecord);
  735. newElement.__rm3Tag001__ = creatorTag;
  736. newElement.__rm3Tag002__ = componentTag;
  737. newElement.__rm3Flg001__ = cntE.__dataEnabled;
  738. // // console.log(5928, cntE.data, cntE.__data)
  739. // if (!defaultValues.has(eKey)){
  740.  
  741. // const o = {};
  742.  
  743. // if('data' in cntE) o.data = cpy(cntE.data);
  744. // if('__data' in cntE) o.__data = cpy(cntE.__data);
  745. // defaultValues.set(eKey, o);
  746.  
  747. // }
  748.  
  749. // if(!noValues.has(eKey)){
  750. // const o = {};
  751. // o.data = true;
  752. // try {
  753.  
  754. // if (!cntE.data) o.data = cntE.data;
  755. // } catch (e) { }
  756.  
  757. // o.__data = true;
  758. // try {
  759.  
  760. // if (!cntE.__data) o.__data = cntE.__data;
  761. // } catch (e) { }
  762. // noValues.set(eKey, o)
  763. // }
  764.  
  765. } else {
  766. // console.log(5920, cntE.__dataReady, cntE.__dataInvalid)
  767. }
  768.  
  769.  
  770. } catch (e) {
  771. console.warn(e);
  772. }
  773. return newElement;
  774.  
  775.  
  776. }
  777.  
  778. document.createElement9512 = document.createElement;
  779. document.createElement = function (a) {
  780. const r = document.createElement9512(a);
  781. try {
  782. const cnt = insp(r);
  783. if (cnt.createComponent_ && !cnt.createComponent9512_) {
  784. const cProto = getProto(r);
  785. if (cProto.createComponent_ === cnt.createComponent_) {
  786.  
  787. if (!cProto.createComponent9512_ && typeof cProto.createComponent_ === 'function' && cProto.createComponent_.length === 3) {
  788.  
  789. cProto.createComponent9512_ = cProto.createComponent_;
  790.  
  791. cProto.createComponent_ = createComponentDefine_;
  792. DEBUG_OPT && hookTos.add(a);
  793. }
  794. } else {
  795.  
  796. if (typeof cnt.createComponent_ === 'function' && cnt.createComponent_.length === 3) {
  797. cnt.createComponent9512_ = cnt.createComponent_;
  798.  
  799. cnt.createComponent_ = createComponentDefine_;
  800. DEBUG_OPT && hookTos.add(a);
  801. }
  802. }
  803.  
  804. }
  805.  
  806. } catch (e) {
  807. console.warn(e)
  808. }
  809.  
  810.  
  811. return r;
  812. }
  813.  
  814. }
  815.  
  816. (rm3.reuseCount = 0); // window.rm3 will be zero initially if this script has no runtime complier error in the initialization phase.
  817.  
  818. })();