diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 000000000..490051876
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+github: iliakan
diff --git a/1-js/01-getting-started/3-code-editors/article.md b/1-js/01-getting-started/3-code-editors/article.md
index 69d35c63d..467b71b24 100644
--- a/1-js/01-getting-started/3-code-editors/article.md
+++ b/1-js/01-getting-started/3-code-editors/article.md
@@ -17,7 +17,7 @@ Si aún no has seleccionado un IDE, considera las siguientes opciones:
 
 Para Windows, también está "Visual Studio", no lo confundamos con "Visual Studio Code". "Visual Studio" es un poderoso editor de pago sólo para Windows, idóneo para la plataforma .NET. Una versión gratuita es de este editor se llama [Visual Studio Community](https://www.visualstudio.com/vs/community/).
 
-Muchos IDEs son de paga, pero tienen un periodo de prueba. Su costo usualmente es pequeño si lo comparamos al salario de un desarrollador calificado, así que sólo escoge el mejor para ti.
+Muchos IDEs son de pago, pero tienen un periodo de prueba. Su costo usualmente es pequeño si lo comparamos al salario de un desarrollador cualificado, así que sólo escoge el mejor para ti.
 
 ## Editores livianos
 
diff --git a/1-js/01-getting-started/4-devtools/article.md b/1-js/01-getting-started/4-devtools/article.md
index f3abf2810..5cac198c2 100644
--- a/1-js/01-getting-started/4-devtools/article.md
+++ b/1-js/01-getting-started/4-devtools/article.md
@@ -22,7 +22,7 @@ Las herramientas de desarrollador se abrirán en la pestaña Consola de forma pr
 
 Se ve algo así:
 
-![chrome](chrome.png)
+![chrome](chrome.webp)
 
 El aspecto exacto de las herramientas de desarrollador depende de su versión de Chrome. Cambia de vez en cuando, pero debería ser similar.
 
@@ -49,7 +49,7 @@ La apariencia de ellos es bastante similar. Una vez que sepa cómo usar una de e
 
 Safari (navegador Mac, no compatible con Windows/Linux) es un poco especial aquí. Necesitamos habilitar primero el "Menú de desarrollo".
 
-Abra Preferencias y vaya al panel "Avanzado". Hay una casilla de verificación en la parte inferior:
+Abra "Configuración" y vaya al panel "Avanzado". Hay una casilla de verificación en la parte inferior:
 
 ![safari](safari.png)
 
diff --git a/1-js/01-getting-started/4-devtools/chrome.png b/1-js/01-getting-started/4-devtools/chrome.png
deleted file mode 100644
index 4cb3ea2f4..000000000
Binary files a/1-js/01-getting-started/4-devtools/chrome.png and /dev/null differ
diff --git a/1-js/01-getting-started/4-devtools/chrome.webp b/1-js/01-getting-started/4-devtools/chrome.webp
new file mode 100644
index 000000000..bdf067079
Binary files /dev/null and b/1-js/01-getting-started/4-devtools/chrome.webp differ
diff --git a/1-js/01-getting-started/4-devtools/chrome@2.webp b/1-js/01-getting-started/4-devtools/chrome@2.webp
new file mode 100644
index 000000000..2aeca5898
Binary files /dev/null and b/1-js/01-getting-started/4-devtools/chrome@2.webp differ
diff --git a/1-js/01-getting-started/4-devtools/chrome@2x.png b/1-js/01-getting-started/4-devtools/chrome@2x.png
deleted file mode 100644
index b87404a8f..000000000
Binary files a/1-js/01-getting-started/4-devtools/chrome@2x.png and /dev/null differ
diff --git a/1-js/02-first-steps/03-strict-mode/article.md b/1-js/02-first-steps/03-strict-mode/article.md
index c98c13258..05dd44122 100644
--- a/1-js/02-first-steps/03-strict-mode/article.md
+++ b/1-js/02-first-steps/03-strict-mode/article.md
@@ -4,7 +4,7 @@ Durante mucho tiempo, JavaScript evolucionó sin problemas de compatibilidad. Se
 
 Esto tenía el beneficio de nunca romper código existente, pero lo malo era que cualquier error o decisión incorrecta tomada por los creadores de JavaScript se quedaba para siempre en el lenguaje.
 
-Esto fue así hasta 2009, cuando ECMAScript 5 (ES5) apareció. Esta versión añadió nuevas características al lenguaje y modificó algunas de las ya existentes. Para mantener el código antiguo funcionando, la mayor parte de las modificaciones están desactivadas por defecto. Tienes que activarlas explícitamente usando una directiva especial: `"use strict"`.
+Esto fue así hasta 2009, cuando ECMAScript 5 (ES5) apareció. Esta versión añadió nuevas características al lenguaje y modificó algunas de las ya existentes. Para mantener el código antiguo funcionando, la mayoría de estas nuevas características están desactivadas por defecto. Tienes que activarlas explícitamente usando una directiva especial: `"use strict"`.
 
 ## "use strict"
 
diff --git a/1-js/02-first-steps/04-variables/article.md b/1-js/02-first-steps/04-variables/article.md
index b9dc9c42b..767d3d323 100644
--- a/1-js/02-first-steps/04-variables/article.md
+++ b/1-js/02-first-steps/04-variables/article.md
@@ -1,6 +1,6 @@
 # Variables
 
-La mayoría del tiempo, una aplicación de JavaScript necesita trabajar con información. Aquí hay 2 ejemplos:
+La mayor parte del tiempo, una aplicación JavaScript necesita trabajar con información. Dos ejemplos:
 1. Una tienda en línea -- La información puede incluir los bienes a la venta y un "carrito de compras".
 2. Una aplicación de chat -- La información puede incluir los usuarios, mensajes, y mucho más.
 
@@ -18,7 +18,7 @@ La siguiente declaración genera (en otras palabras: *declara* o *define*) una v
 let message;
 ```
 
-Ahora podemos introducir datos en ella al utilizar el operador de asignación `=`:
+Ahora podemos introducir datos en ella, utilizando el operador de asignación `=`:
 
 ```js
 let message;
@@ -47,7 +47,7 @@ let message = 'Hola!'; // define la variable y asigna un valor
 alert(message); // Hola!
 ```
 
-También podemos declarar variables múltiples en una sola línea:
+También podemos declarar múltiples variables en una sola línea:
 
 ```js no-beautify
 let user = 'John', age = 25, message = 'Hola';
@@ -63,7 +63,7 @@ let age = 25;
 let message = 'Hola';
 ```
 
-Algunas personas también definen variables múltiples en estilo multilínea:
+Hay quienes prefieren definir múltiples variables en estilo multilínea:
 
 ```js no-beautify
 let user = 'John',
@@ -71,7 +71,7 @@ let user = 'John',
   message = 'Hola';
 ```
 
-...Incluso en este estilo "coma primero":
+... o con el estilo "coma primero":
 
 ```js no-beautify
 let user = 'John'
@@ -97,7 +97,7 @@ Existen sutiles diferencias entre `let` y `var`, pero no nos interesan en este m
 
 Podemos comprender fácilmente el concepto de una "variable" si nos la imaginamos como una "caja" con una etiqueta de nombre único pegada en ella.
 
-Por ejemplo, podemos imaginar la variable `message` como una caja etiquetada `"message"` con el valor `"Hola!"` adentro:
+Por ejemplo, la variable `message` puede ser imaginada como una caja etiquetada `"message"` con el valor `"Hola!"` dentro:
 
 ![](variable.svg)
 
@@ -205,7 +205,7 @@ let имя = '...';
 let 我 = '...';
 ```
 
-Técnicamente, no existe ningún error aquí. Tales nombres están permitidos, pero existe una tradición internacional de utilizar inglés en el nombramiento de variables. Incluso si estamos escribiendo un script pequeño, este puede tener una larga vida por delante. Puede ser necesario que gente de otros países deba leerlo en algún momento.
+Técnicamente, no existe error aquí. Tales nombres están permitidos, pero internacionalmente existe la convención de utilizar el inglés para el nombre de las variables. Incluso si estamos escribiendo un script pequeño, este puede tener una larga vida por delante. Gente de otros países puede necesitar leerlo en algún momento.
 ````
 
 ````warn header="Nombres reservados"
@@ -260,7 +260,7 @@ const myBirthday = '18.04.1982';
 myBirthday = '01.01.2001'; // ¡error, no se puede reasignar la constante!
 ```
 
-Cuando un programador está seguro de que una variable nunca cambiará, puede declarar la variable con `const` para garantizar y comunicar claramente este hecho a todos.
+Cuando un programador está seguro de que una variable nunca cambiará, puede declararla con `const` para garantizar esto y comunicarlo claramente a los demás.
 
 ### Constantes mayúsculas
 
@@ -297,9 +297,9 @@ Por ejemplo:
 const pageLoadTime = /* el tiempo que tardó la página web para cargar */;
 ```
 
-El valor de `pageLoadTime` no se conoce antes de cargar la página, así que la nombramos normalmente. No obstante, es una constante porque no cambia después de su asignación inicial.
+El valor de `pageLoadTime` no está preestablecido. Como no se conoce antes de cargar la página, la nombramos normalmente. Pero podemos declararla como constante, porque después de su asignación inicial, no cambiará.
 
-En otras palabras, las constantes con nombres en mayúscula son utilizadas solamente como alias para valores invariables y preestablecidos ("hard-coded").
+En otras palabras, las constantes en mayúsculas son utilizadas solamente como alias para valores invariables y preestablecidos.
 
 ## Nombrar cosas correctamente
 
@@ -309,16 +309,16 @@ Una variable debe tener un nombre claro, de significado evidente, que describa e
 
 Nombrar variables es una de las habilidades más importantes y complejas en la programación. Un vistazo rápido a el nombre de las variables nos revela cuál código fue escrito por un principiante o por un desarrollador experimentado.
 
-En un proyecto real, la mayor parte de el tiempo se pasa modificando y extendiendo una base de código en vez de empezar a escribir algo desde cero. Cuando regresamos a algún código después de hacer algo distinto por un rato, es mucho más fácil encontrar información que está bien etiquetada. O, en otras palabras, cuando las variables tienen nombres adecuados.
+En un proyecto real, se pasa mucho más tiempo modificando y extendiendo una base de código existente que escribiendo algo nuevo desde cero. Cuando regresamos a nuestro código luego de un tiempo, es mucho más fácil encontrar información que está bien etiquetada. O en otras palabras, cuando las variables tienen los nombres adecuados.
 
-Por favor pasa tiempo pensando en el nombre adecuado para una variable antes de declararla. Hacer esto te da un retorno muy sustancial.
+Por favor, dedica tiempo para pensar un nombre correcto para una variable antes de declararla. Hacer esto te rendirá muy bien.
 
 Algunas reglas buenas para seguir:
 
-- Use términos legibles para humanos como `userName` p `shoppingCart`.
-- Evite abreviaciones o nombres cortos `a`, `b`, `c`, al menos que en serio sepa lo que está haciendo.
-- Cree nombres que describen al máximo lo que son y sean concisos. Ejemplos que no son adecuados son `data` y `value`. Estos nombres no nos dicen nada. Estos solo está bien usarlos en el contexto de un código que deje excepcionalmente obvio cuál valor o cuales datos está referenciando la variable.
-- Acuerda en tu propia mente y con tu equipo cuáles términos se utilizarán. Si a un visitante se le llamara "user", debemos llamar las variables relacionadas `currentUser` o `newUser` en vez de `currentVisitor` o `newManInTown`.
+- Usa términos legibles para humanos como `userName` p `shoppingCart`.
+- Evita abreviaciones o nombres cortos `a`, `b`, `c`, a menos que realmente sepas lo que estás haciendo.
+- Crea nombres que describan al máximo lo que son y sean concisos. Ejemplos de nombres malos son `data` y `value`. Estos nombres no nos dicen nada, solo son adecuados en el contexto de un código que deje excepcionalmente obvio cuál dato o valor está referenciando la variable.
+- Ponte de acuerdo con tu equipo, y con tu propia mente, cuáles términos se utilizarán. Si a un visitante se lo llamara "user", debemos llamar las variables relacionadas `currentUser` o `newUser` en vez de `currentVisitor` o `newManInTown`.
 
 ¿Suena simple? De hecho lo es, pero no es tan fácil crear nombres de variables descriptivos y concisos a la hora de practicar. Inténtelo.
 
@@ -329,9 +329,9 @@ El resultado de esto es que sus variables son como cajas en las cuales la gente
 
 Dichos programadores se ahorran un poco durante la declaración de la variable, pero pierden diez veces más a la hora de depuración.
 
-Una variable extra es algo bueno, no algo malvado.
+Una variable extra es algo bueno, no algo diabólico.
 
-Los minificadores de JavaScript moderno, y los navegadores optimizan el código suficientemente bien para no generar cuestiones de rendimiento. Utilizar diferentes variables para distintos valores incluso puede ayudar a optimizar su código
+Los navegadores modernos y los minificadores de JavaScript optimizan el código, así que esto no impacta en el rendimiento. Utilizar diferentes variables para distintos valores incluso puede ayudar a optimizar tu código.
 ```
 
 ## Resumen
@@ -340,6 +340,6 @@ Podemos declarar variables para almacenar datos al utilizar las palabra clave `v
 
 - `let` -- es la forma moderna de declaración de una variable.
 - `var` -- es la declaración de variable de vieja escuela. Normalmente no lo utilizamos en absoluto. Cubriremos sus sutiles diferencias con `let` en el capítulo <info:var>, por si lo necesitaras.
-- `const` -- es como `let`, pero el valor de la variable no puede ser alterado.
+- `const` -- es como `let`, pero una vez asignado, el valor de la variable no podrá alterarse.
 
 Las variables deben ser nombradas de tal manera que entendamos fácilmente lo que está en su interior.
diff --git a/1-js/02-first-steps/05-types/article.md b/1-js/02-first-steps/05-types/article.md
index f74b398fb..24bf592ec 100644
--- a/1-js/02-first-steps/05-types/article.md
+++ b/1-js/02-first-steps/05-types/article.md
@@ -94,13 +94,6 @@ const bigInt = 1234567890123456789012345678901234567890n;
 
 Como los números `BigInt` rara vez se necesitan, no los cubrimos aquí sino que les dedicamos un capítulo separado <info: bigint>. Léelo cuando necesites números tan grandes.
 
-
-```smart header="Problemas de compatibilidad"
-En este momento, `BigInt` está soportado por Firefox/Chrome/Edge/Safari, pero no por IE.
-```
-
-Puedes revisar la [tabla de compatibilidad de BigInt en *MDN*](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) para saber qué versiones de navegador tienen soporte.
-
 ## String
 
 Un *string* en JavaScript es una cadena de caracteres y debe colocarse entre comillas.
diff --git a/1-js/02-first-steps/08-operators/article.md b/1-js/02-first-steps/08-operators/article.md
index 21de63e68..8a78dbf70 100644
--- a/1-js/02-first-steps/08-operators/article.md
+++ b/1-js/02-first-steps/08-operators/article.md
@@ -442,9 +442,9 @@ Estos operadores se usan muy raramente, cuando necesitamos manejar la representa
 
 ## Coma
 
-El operador coma `,` es uno de los operadores más raros e inusuales. A veces, es utilizado para escribir código más corto, entonces tenemos que saberlo para poder entender qué está pasando.
+El operador coma `,` es uno de los operadores más raros e inusuales. A veces se utiliza para escribir código más corto, por lo que debemos conocerlo para poder entender lo que está sucediendo.
 
-El operador coma nos permite evaluar varias expresiones, dividiéndolas con una coma `,`. Cada una de ellas es evaluada, pero sólo el resultado de la última es devuelto.
+El operador coma nos permite evaluar varias expresiones, separándolas con una coma `,`. Cada expresión se evalúa, pero sólo se devuelve el resultado de la última.
 
 Por ejemplo:
 
@@ -466,7 +466,7 @@ Sin ellos: `a = 1 + 2, 3 + 4` se evalúa primero el `+`, sumando los números a
 
 ¿Por qué necesitamos un operador que deseche todo excepto la última expresión?
 
-A veces, las personas lo usan en construcciones más complejas para poner varias acciones en una línea.
+A veces se utilizan en construcciones más complejas para ejecutar varias acciones en una línea.
 
 Por ejemplo:
 
@@ -477,4 +477,4 @@ for (*!*a = 1, b = 3, c = a * b*/!*; a < 10; a++) {
 }
 ```
 
-Tales trucos se usan en muchos frameworks de JavaScript. Por eso los estamos mencionando. Pero generalmente no mejoran la legibilidad del código, por lo que debemos pensar bien antes de usarlos.
+Tales trucos se usan en muchos frameworks de JavaScript, por eso los mencionamos. Sin embargo, generalmente no mejoran la legibilidad del código, por lo que debemos pensar bien antes de usarlos.
diff --git a/1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/task.md b/1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/task.md
index e5a75c83f..7a3c42383 100644
--- a/1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/task.md
+++ b/1-js/02-first-steps/10-ifelse/6-rewrite-if-else-question/task.md
@@ -6,7 +6,7 @@ importance: 5
 
 Reescriba el `if..else` utilizando operadores ternarios múltiples`'?'`.
 
-Para legibilidad, es recomendad dividirlo en múltiples lineas de código.
+Para mejor legibilidad, se recomienda dividirlo en múltiples lineas de código.
 
 ```js
 let message;
diff --git a/1-js/02-first-steps/10-ifelse/article.md b/1-js/02-first-steps/10-ifelse/article.md
index f62d71ddf..6005dfa19 100644
--- a/1-js/02-first-steps/10-ifelse/article.md
+++ b/1-js/02-first-steps/10-ifelse/article.md
@@ -37,13 +37,13 @@ La sentencia `if (…)` evalúa la expresión dentro de sus paréntesis y convie
 
 Recordemos las reglas de conversión del capítulo <info:type-conversions>:
 
-- El número `0`, un string vacío `""`, `null`, `undefined`, y `NaN`, se convierten en `false`. Por esto son llamados valores "falsos".
-- El resto de los valores se convierten en `true`, entonces los llamaremos valores "verdaderos".
+- Los valores: número `0`, string vacío `""`, `null`, `undefined`, y `NaN`, en un contexto booleano se convierten en `false`. Por ello, sin ser booleanos, se los conoce como valores "falsy".
+- El resto de los valores se convierten en `true`, y son valores que llamamos "truthy".
 
 Entonces, el código bajo esta condición nunca se ejecutaría:
 
 ```js
-if (0) { // 0 es falso
+if (0) { // 0 es falsy
   ...
 }
 ```
@@ -51,7 +51,7 @@ if (0) { // 0 es falso
 ...y dentro de esta condición siempre se ejecutará:
 
 ```js
-if (1) { // 1 es verdadero
+if (1) { // 1 es truthy
   ...
 }
 ```
@@ -59,7 +59,7 @@ if (1) { // 1 es verdadero
 También podemos pasar un valor booleano pre-evaluado al `if`, así:
 
 ```js
-let cond = (year == 2015); // la igualdad evalúa y devuelve un true o false
+let cond = (year == 2015); // la igualdad se evalúa y devuelve un true o false
 
 if (cond) {
   ...
@@ -68,7 +68,7 @@ if (cond) {
 
 ## La cláusula "else"
 
-La sentencia `if` puede contener un bloque `else` ("si no", "en caso contrario") opcional. Este bloque se ejecutará cuando la condición sea falsa.
+La sentencia `if` puede contener un bloque `else` ("si no", "en caso contrario") opcional. Este bloque se ejecuta cuando la condición resulta falsa.
 
 Por ejemplo:
 ```js run
@@ -133,7 +133,7 @@ La Sintaxis es:
 let result = condition ? value1 : value2;
 ```
 
-Se evalúa `condition`: si es verdadera entonces devuelve `value1` , de lo contrario `value2`.
+Se evalúa `condition`: si resulta verdadera entonces devuelve `value1` , de lo contrario `value2`.
 
 Por ejemplo:
 
diff --git a/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/solution.md b/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/solution.md
index 9cd356a62..23fc22258 100644
--- a/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/solution.md
+++ b/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/solution.md
@@ -1,4 +1,4 @@
-La respuesta es `2`, ese es el primer valor verdadero.
+La respuesta es `2`, ese es el primer valor truthy.
 
 ```js run
 alert( null || 2 || undefined );
diff --git a/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md b/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md
index acccef7d6..73eea0b53 100644
--- a/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md
+++ b/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md
@@ -4,10 +4,10 @@ La repuesta: primero `1`, después `2`.
 alert( alert(1) || 2 || alert(3) );
 ```
 
-La llamada a `alert` no retorna un valor. O, en otras palabras, retorna `undefined`.
+Una llamada a `alert` no retorna un valor relevante. Siempre retorna `undefined`.
 
-1. El primer OR `||` evalúa el operando de la izquierda `alert(1)`. Eso muestra el primer mensaje con `1`.
-2. El `alert` retorna `undefined`, por lo que OR se dirige al segundo operando buscando un valor verdadero.
-3. El segundo operando `2` es un valor verdadero, por lo que se detiene la ejecución, se retorna `2` y es mostrado por el alert exterior.
+1. El primer OR `||` comienza evaluando el operando de la izquierda `alert(1)`. Este alert muestra el primer mensaje con `1`.
+2. Ese mismo `alert` retorna `undefined`, por lo que OR se dirige al segundo operando buscando un valor truthy.
+3. El segundo operando `2` es un valor truthy, por lo que el OR detiene su ejecución y retorna el 2. Este 2 es luego mostrado por el alert exterior.
 
-No habrá `3` debido a que la evaluación no alcanza a `alert(3)`.
+No habrá `3` debido a que la evaluación nunca alcanza a `alert(3)`.
diff --git a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md
index 0ceba5d2a..f926c6dfe 100644
--- a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md
+++ b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md
@@ -1,4 +1,4 @@
-La respuesta: `null`, porque es el primer valor falso de la lista.
+La respuesta: `null`, porque es el primer valor falsy de la lista.
 
 ```js run
 alert(1 && null && 2);
diff --git a/1-js/02-first-steps/11-logical-operators/4-alert-and/solution.md b/1-js/02-first-steps/11-logical-operators/4-alert-and/solution.md
index 1f1b494ef..a6aa8780d 100644
--- a/1-js/02-first-steps/11-logical-operators/4-alert-and/solution.md
+++ b/1-js/02-first-steps/11-logical-operators/4-alert-and/solution.md
@@ -4,6 +4,6 @@ La respuesta: `1` y después `undefined`.
 alert( alert(1) && alert(2) );
 ```
 
-La llamada a `alert` retorna `undefined` (solo muestra un mensaje, así que no hay un valor que retornar relevante)
+Una llamada a `alert` siempre retorna `undefined` (solo muestra un mensaje, no tiene un valor relevante que retornar)
 
-Debido a ello, `&&` evalúa el operando de la izquierda (imprime `1`) e inmediatamente se detiene porque `undefined` es un valor falso. Como `&&` busca un valor falso y lo retorna, terminamos.
+Debido a ello, `&&` evalúa el operando de la izquierda (el cual imprime `1`) e inmediatamente se detiene porque `undefined` es falsy. Como `&&` busca un valor falsy, lo retorna y termina.
diff --git a/1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md b/1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md
index 4903143d7..b99056a48 100644
--- a/1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md
+++ b/1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md
@@ -12,5 +12,5 @@ El resultado de `2 && 3 = 3`, por lo que la expresión se convierte en:
 null || 3 || 4
 ```
 
-Ahora el resultado será el primer valor verdadero: `3`.
+Ahora el resultado será el primer valor truthy: `3`.
 
diff --git a/1-js/02-first-steps/11-logical-operators/8-if-question/solution.md b/1-js/02-first-steps/11-logical-operators/8-if-question/solution.md
index f9ce47b32..e81c631a2 100644
--- a/1-js/02-first-steps/11-logical-operators/8-if-question/solution.md
+++ b/1-js/02-first-steps/11-logical-operators/8-if-question/solution.md
@@ -4,11 +4,11 @@ Detalles:
 
 ```js run
 // Corre.
-// El resultado de -1 || 0 = -1, valor verdadero
+// El resultado de -1 || 0 es -1, valor truthy
 if (-1 || 0) alert( "primero" );
 
 // No corre.
-// -1 && 0 = 0, valor falso
+// -1 && 0 es 0, valor falsy
 if (-1 && 0) alert( "segundo" );
 
 // Se ejecuta
diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/task.md b/1-js/02-first-steps/11-logical-operators/9-check-login/task.md
index 60e00ad49..d2ed2db8a 100644
--- a/1-js/02-first-steps/11-logical-operators/9-check-login/task.md
+++ b/1-js/02-first-steps/11-logical-operators/9-check-login/task.md
@@ -6,12 +6,12 @@ importance: 3
 
 Escribe un código que pregunte por el inicio de sesión con `propmt`.
 
-Si el visitante ingresa `"Admin"`, entonces `prompt`(pregunta) por una contraseña, si la entrada es una linea vacía o `key:Esc` -- muestra "Cancelado.", si es otra cadena de texto -- entonces muestra "No te conozco".
+Si el visitante ingresa `"Admin"`, entonces debe pedir una contraseña (con un nuevo `propmt`). Si la entrada es una linea vacía o `key:Esc`, entonces muestra "Cancelado.". Si es otra cadena de texto, entonces muestra "No te conozco".
 
 La contraseña se comprueba de la siguiente manera:
 
 -  Si es igual a "TheMaster", entonces muestra "Bienvenido!",
--  Si es otra cadena de texto -- muetra "Contraseña incorrecta",
+-  Si es otra cadena de texto, muetra "Contraseña incorrecta",
 -  Para una cadena de texto vacía o una entrada cancelada, muestra "Cancelado."
 
 El esquema:
diff --git a/1-js/02-first-steps/11-logical-operators/article.md b/1-js/02-first-steps/11-logical-operators/article.md
index de2ce5591..5805a37f0 100644
--- a/1-js/02-first-steps/11-logical-operators/article.md
+++ b/1-js/02-first-steps/11-logical-operators/article.md
@@ -35,7 +35,7 @@ Por ejemplo, el número `1` es tratado como `true`, el número `0` como `false`:
 
 ```js run
 if (1 || 0) { // Funciona como if( true || false )
-	alert("valor verdadero!");
+	alert("¡valor truthy!");
 }
 ```
 
@@ -94,14 +94,14 @@ alert(1 || 0); // 1 (1 es un valor verdadero)
 alert(null || 1); // 1 (1 es el primer valor verdadero)
 alert(null || 0 || 1); // 1 (el primer valor verdadero)
 
-alert(undefined || null || 0); // 0 (todos son valores falsos, retorna el último valor)
+alert(undefined || null || 0); // 0 (todos son valores falsy, retorna el último valor)
 ```
 
 Esto brinda varios usos interesantes comparados al "OR puro, clásico, de solo booleanos".
 
 1. **Obtener el primer valor verdadero de una lista de variables o expresiones.**
 
-   Por ejemplo, tenemos las variables `firstName`, `lastName` y `nickName`, todas opcionales (pueden ser undefined o tener valores falsos).
+   Por ejemplo, tenemos las variables `firstName`, `lastName` y `nickName`, todas opcionales (pueden ser undefined o tener valores falsy).
 
    Usemos OR `||` para elegir el que tiene los datos y mostrarlo (o anónimo si no hay nada configurado):
 
@@ -115,7 +115,7 @@ Esto brinda varios usos interesantes comparados al "OR puro, clásico, de solo b
    */!*
    ```
 
-    Si todas las variables fueran falsas, aparecería `"Anonymous"`. 
+    Si todas las variables fueran falsy, aparecería `"Anonymous"`. 
 
 2. **Evaluación del camino más corto.**
 
@@ -134,7 +134,7 @@ Esto brinda varios usos interesantes comparados al "OR puro, clásico, de solo b
 
     En la primera línea, el operador OR `||` detiene la evaluación inmediatamente después de ver que es verdadera, por lo que la alerta no se ejecuta.
 
-    A veces se usa esta función para ejecutar comandos solo si la condición en la parte izquierda es falsa.
+    A veces se usa esta función para ejecutar comandos solo si la condición en la parte izquierda es falsy.
 
 ## && (AND)
 
@@ -168,11 +168,11 @@ Al igual que con OR, cualquier valor es permitido como operando de AND:
 
 ```js run
 if (1 && 0) { // evaluado como true && false
-  alert( "no funcionará porque el resultado es un valor falso" );
+  alert( "no funcionará porque el resultado es un valor falsy" );
 }
 ```
 
-## AND "&&" encuentra el primer valor falso
+## AND "&&" encuentra el primer valor falsy
 
 Dado múltiples valores aplicados al operador AND:
 
@@ -184,27 +184,27 @@ El operador AND `&&` realiza lo siguiente:
 
 -  Evalúa los operandos de izquierda a derecha.
 -  Para cada operando, los convierte a un booleano. Si el resultado es `false`, se detiene y retorna el valor original de dicho operando.
--  Si todos los operandos han sido evaluados (todos fueron valores verdaderos), retorna el último operando.
+-  Si todos los operandos han sido evaluados (todos fueron valores truthy), retorna el último operando.
 
-En otras palabras, AND retorna el primer valor falso o el último valor si ninguno fue encontrado.
+En otras palabras, AND retorna el primer valor falsy o el último valor si ninguno fue encontrado.
 
-Las reglas anteriores son similares a las de OR. La diferencia es que AND retorna el primer valor *falso* mientras que OR retorna el primer valor *verdadero*.
+Las reglas anteriores son similares a las de OR. La diferencia es que AND retorna el primer valor *falsy* mientras que OR retorna el primer valor *truthy*.
 
 Ejemplo:
 
 ```js run
-// si el primer operando es un valor verdadero,
+// si el primer operando es un valor truthy,
 // AND retorna el segundo operando:
 alert(1 && 0); // 0
 alert(1 && 5); // 5
 
-// si el primer operando es un valor falso,
+// si el primer operando es un valor falsy,
 // AND lo retorna. El segundo operando es ignorado
 alert(null && 5); // null
 alert(0 && "cualquier valor"); // 0
 ```
 
-También podemos pasar varios valores de una vez. Observa como el primer valor falso es retornado: 
+También podemos pasar varios valores de una vez. Observa como el primer valor falsy es retornado: 
 
 ```js run
 alert(1 && 2 && null && 3); // null
diff --git a/1-js/02-first-steps/16-function-expressions/article.md b/1-js/02-first-steps/16-function-expressions/article.md
index c16f56e9e..245f29062 100644
--- a/1-js/02-first-steps/16-function-expressions/article.md
+++ b/1-js/02-first-steps/16-function-expressions/article.md
@@ -82,7 +82,7 @@ let sayHi = function() { // (1) crea
   alert( "Hola" );
 };
 
-let func = sayHi;
+let func = sayHi;  //(2)
 // ...
 ```
 
diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md
index df640f023..18ce69019 100644
--- a/1-js/03-code-quality/06-polyfills/article.md
+++ b/1-js/03-code-quality/06-polyfills/article.md
@@ -7,7 +7,7 @@ Los equipos de desarrollo detrás de los intérpretes (engines) de JavaScript ti
 
 Por lo tanto, es bastante común para un intérprete implementar solo parte del estándar.
 
-Una buena página para ver el estado actual de soporte de características del lenguaje es <https://kangax.github.io/compat-table/es6/> (es grande, todavía tenemos mucho que aprender).
+Una buena página para ver el estado actual de soporte de características del lenguaje es <https://compat-table.github.io/compat-table/es6/> (es grande, todavía tenemos mucho que aprender).
 
 Como programadores, queremos las características más recientes. Cuanto más, ¡mejor!
 
@@ -71,10 +71,7 @@ if (!Math.trunc) { // no existe tal función
 
 JavaScript es un lenguaje muy dinámico, los scripts pueden agregar o modificar cualquier función, incluso las integradas. 
 
-Dos librerías interesantes de polyfills son:
-- [core js](https://github.com/zloirock/core-js) - da muchísimo soporte, pero permite que se incluyan solamente las características necesitadas.
-- [polyfill.io](https://polyfill.io) - servicio que brinda un script con polyfills dependiendo de las características del navegador del usuario.
-
+Una librería interesante polyfill es [core js](https://github.com/zloirock/core-js), que brinda una amplia gama de catacterísticas y te permite incluir solo las que necesitas.
 
 ## Resumen
 
@@ -85,7 +82,7 @@ Pero no olvides usar transpiladores (si usas sintaxis u operadores modernos) y p
 Por ejemplo, cuando estés más familiarizado con JavaScript puedes configurar la construcción de código basado en [webpack](https://webpack.js.org/) con el plugin [babel-loader](https://github.com/babel/babel-loader).
 
 Buenos recursos que muestran el estado actual de soporte para varias característica:
-- <https://kangax.github.io/compat-table/es6/> - para JavaScript puro.
+- <https://compat-table.github.io/compat-table/es6/> - para JavaScript puro.
 - <https://caniuse.com/> - para funciones relacionadas al navegador.
 
 P.S. Google Chrome usualmente es el más actualizado con las características del lenguaje, pruébalo si algún demo del tutorial falla. Aunque la mayoría de los demos funciona con cualquier navegador moderno.
diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md b/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md
index 4a0514bcc..cf8c8a5ed 100644
--- a/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md
+++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md
@@ -21,7 +21,7 @@ let ladder = {
 };
 ```
 
-Ahora, si necesitamos hacer varios llamados en secuencia podemos hacer algo como esto:
+Si ahora necesitamos hacer varios llamados en secuencia, podemos hacer algo como esto:
 
 ```js
 ladder.up();
@@ -32,10 +32,10 @@ ladder.down();
 ladder.showStep(); // 0
 ```
 
-Modifica el código de "arriba" `up`, "abajo" `down` y "mostrar peldaño" `showStep` para hacer los llamados encadenables como esto:
+Modifica el código de "arriba" `up`, "abajo" `down` y "mostrar peldaño" `showStep` para hacer los llamados encadenables. Así:
 
 ```js
-ladder.up().up().down().showStep().down().showStep(); // shows 1 then 0
+ladder.up().up().down().showStep().down().showStep(); // muestra 1 luego 0
 ```
 
-Tal enfoque es ampliamente usado entre las librerías JavaScript.
+Tal enfoque es ampliamente usado en librerías JavaScript.
diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md
index 0d8f9d411..0e1d2b0a8 100644
--- a/1-js/05-data-types/02-number/article.md
+++ b/1-js/05-data-types/02-number/article.md
@@ -4,7 +4,7 @@ En JavaScript moderno, hay dos tipos de números:
 
 1. Los números regulares en JavaScript son almacenados con el formato de 64-bit [IEEE-754](https://es.wikipedia.org/wiki/IEEE_754), conocido como "números de doble precisión de coma flotante". Estos números son los que estaremos usando la mayor parte del tiempo, y hablaremos de ellos en este capítulo.
 
-2. Los números BigInt representan enteros de longitud arbitraria. A veces son necesarios porque un número regular no puede exceder <code>2<sup>53</sup></code> ni ser menor a <code>-2<sup>53</sup></code> manteniendo la precisión, algo que mencionamos antes en el capítulo <info:types>. Como los bigints son usados en algunas áreas especiales, les dedicamos un capítulo especial <info:bigint>.
+2. Los números BigInt representan enteros de longitud arbitraria. A veces son necesarios porque un número entero regular no puede exceder <code>2<sup>53</sup></code> ni ser menor a <code>-2<sup>53</sup></code> manteniendo la precisión, algo que mencionamos antes en el capítulo <info:types>. Como los bigints son usados en áreas muy especiales, les dedicamos un capítulo especial <info:bigint>.
 
 Aquí hablaremos de números regulares. Ampliemos lo que ya sabemos de ellos.
 
@@ -107,9 +107,9 @@ La `base` puede variar entre `2` y `36`. La predeterminada es `10`.
 
 Casos de uso común son:
 
-- **base=16** usada para colores hex, codificación de caracteres, etc; los dígitos pueden ser `0..9` o `A..F`.
-- **base=2** mayormente usada para el debug de operaciones de bit, los dígitos pueden ser `0` o `1`.
-- **base=36** Es el máximo, los dígitos pueden ser `0..9` o `A..Z`.  Aquí el alfabeto inglés completo es usado para representar un número.  Un uso peculiar pero práctico para la base `36` es cuando necesitamos convertir un largo identificador numérico en algo más corto, por ejemplo para abreviar una url. Podemos simplemente representarlo en el sistema numeral de base `36`:
+- **base=16** usada para colores en hexa, codificación de caracteres, etc.; los dígitos pueden ser `0..9` o `A..F`.
+- **base=2** mayormente usada para la depuración de operaciones de bit, los dígitos pueden ser `0` o `1`.
+- **base=36** Es la base máxima, los dígitos pueden ser `0..9` o `A..Z`.  Aquí el alfabeto inglés completo es usado para representar un número. Un uso peculiar pero práctico para la base `36` es cuando necesitamos convertir un largo identificador numérico en algo más corto, por ejemplo para abreviar una url. Podemos simplemente representarlo en el sistema numeral de base `36`:
 
     ```js run
     alert( 123456..toString(36) ); // 2n9c
@@ -118,7 +118,7 @@ Casos de uso común son:
 ```warn header="Dos puntos para llamar un método"
 Por favor observa que los dos puntos en `123456..toString(36)` no son un error tipográfico. Si queremos llamar un método directamente sobre el número, como `toString` del ejemplo anterior, necesitamos ubicar los dos puntos `..` tras él.
 
-Si pusiéramos un único punto: `123456.toString(36)`, habría un error, porque la sintaxis de JavaScript implica una parte decimal después del primer punto. Al poner un punto más, JavaScript reconoce que la parte decimal está vacía y luego va el método.
+Si pusiéramos un único punto: `123456.toString(36)`, habría un error, porque la sintaxis de JavaScript espera una parte decimal después del primer punto. Al ver el segundo punto, JavaScript reconoce que la parte decimal está vacía y le sigue un método.
 
 También podríamos escribir `(123456).toString(36)`.
 
@@ -137,7 +137,7 @@ Hay varias funciones incorporadas para el redondeo:
 : Redondea hacia arriba: `3.1` torna en `4`, y `-1.1` torna en `-1`.
 
 `Math.round`
-: Redondea hacia el entero más cercano: `3.1` redondea a `3`, `3.6` redondea a `4`, el caso medio `3.5` redondea a `4` también.
+: Redondea hacia el entero más cercano: `3.1` redondea a `3`, `3.6` redondea a `4`; los casos medios `3.5` redondea a `4`, y `-3.5` redondea a `-3`.
 
 `Math.trunc` (no soportado en Internet Explorer)
 : Remueve lo que haya tras el punto decimal sin redondear: `3.1` torna en `3`, `-1.1` torna en `-1`.
@@ -147,8 +147,10 @@ Aquí, la tabla que resume las diferencias entre ellos:
 |   | `Math.floor` | `Math.ceil` | `Math.round` | `Math.trunc` |
 |---|---------|--------|---------|---------|
 |`3.1`|  `3`    |   `4`  |    `3`  |   `3`   |
+|`3.5`|  `3`    |   `4`  |    `4`  |   `3`   |
 |`3.6`|  `3`    |   `4`  |    `4`  |   `3`   |
 |`-1.1`|  `-2`    |   `-1`  |    `-1`  |   `-1`   |
+|`-1.5`|  `-2`    |   `-1`  |    `-1`  |   `-1`   |
 |`-1.6`|  `-2`    |   `-1`  |    `-2`  |   `-1`   |
 
 
@@ -188,7 +190,7 @@ Hay dos formas de hacerlo:
     alert( num.toFixed(5) ); // "12.34000", con ceros agregados para dar exactamente 5 dígitos
     ```
 
-    Podemos convertirlo a "number" usando el operador unario más o llamando a `Number()`; por ejemplo, escribir `+num.toFixed(5)`.
+    Podemos convertirlo a `number` usando el operador unario más `+` o llamando a `Number()`. Por ejemplo, `+num.toFixed(5)`.
 
 ## Cálculo impreciso
 
@@ -222,7 +224,13 @@ alert( 0.1 + 0.2 ); // 0.30000000000000004
 
 Un número es almacenado en memoria en su forma binaria, una secuencia de bits, unos y ceros. Pero decimales como `0.1`, `0.2` que se ven simples en el sistema decimal son realmente fracciones sin fin en su forma binaria.
 
-¿Qué es `0.1`? Es un uno dividido por 10 `1/10`, un décimo. En sistema decimal es fácilmente representable. Compáralo con un tercio: `1/3`, se vuelve una fracción sin fin `0.33333(3)`.
+```js run
+alert(0.1.toString(2)); // 0.0001100110011001100110011001100110011001100110011001101
+alert(0.2.toString(2)); // 0.001100110011001100110011001100110011001100110011001101
+alert((0.1 + 0.2).toString(2)); // 0.0100110011001100110011001100110011001100110011001101
+```
+
+¿Qué es `0.1`? Es un uno dividido por 10, `1/10`, un décimo. En sistema decimal es fácilmente representable. Compáralo con un tercio: `1/3`, que se vuelve una fracción sin fin `0.33333(3)`.
 
 Así, la división en potencias de diez garantizan un buen funcionamiento en el sistema decimal, pero divisiones por `3` no.  Por la misma razón, en el sistema binario la división en potencias de `2` garantizan su funcionamiento, pero `1/10` se vuelve una fracción binaria sin fin.
 
@@ -235,14 +243,14 @@ Podemos verlo en acción:
 alert( 0.1.toFixed(20) ); // 0.10000000000000000555
 ```
 
-Y cuando sumamos dos números, se apilan sus "pérdidas de precisión".
+Y cuando sumamos dos números, sus "pérdidas de precisión" se acumulan.
 
 Y es por ello que `0.1 + 0.2` no es exactamente `0.3`.
 
 ```smart header="No solo JavaScript"
 El mismo problema existe en muchos otros lenguajes de programación.
 
-PHP, Java, C, Perl, Ruby dan exactamente el mismo resultado, porque ellos están basados en el mismo formato numérico.
+PHP, Java, C, Perl, Ruby, dan exactamente el mismo resultado, porque ellos están basados en el mismo formato numérico.
 ```
 
 ¿Podemos resolver el problema? Seguro, la forma más confiable es redondear el resultado con la ayuda de un método. [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed):
@@ -348,7 +356,7 @@ Los métodos [Number.isNaN](https://developer.mozilla.org/es/docs/Web/JavaScript
     alert( isNaN("str") ); // true, porque isNaN convierte el string "str" a number y obtiene NaN como resultado de su conversión
     ```
 
-- `Number.isFinite(value)` devuelve `true` si el argumento pertenece al tipo de dato `number` y no es  `NaN/Infinity/-Infinity`. En cualquier otro caso devuelve `false`.
+- `Number.isFinite(value)` devuelve `true` si el argumento pertenece al tipo de dato `number` y no es `NaN/Infinity/-Infinity`. En cualquier otro caso devuelve `false`.
 
     ```js run
     alert( Number.isFinite(123) ); // true
diff --git a/1-js/05-data-types/04-array/article.md b/1-js/05-data-types/04-array/article.md
index ec4803919..96e492bbb 100644
--- a/1-js/05-data-types/04-array/article.md
+++ b/1-js/05-data-types/04-array/article.md
@@ -426,7 +426,7 @@ let matrix = [
   [7, 8, 9]
 ];
 
-alert( matrix[1][1] ); // 5, el elemento central
+alert( matrix[0][1] ); // 2, el segundo valor del primer array interno
 ```
 
 ## toString
diff --git a/1-js/05-data-types/05-array-methods/article.md b/1-js/05-data-types/05-array-methods/article.md
index 336975aeb..f0891d95e 100644
--- a/1-js/05-data-types/05-array-methods/article.md
+++ b/1-js/05-data-types/05-array-methods/article.md
@@ -1,6 +1,6 @@
 # Métodos de arrays 
 
-Los arrays (también llamados arreglos o matrices) cuentan con muchos métodos. Para hacer las cosas más sencillas, en este capítulo se encuentran divididos en dos partes.
+Los arrays (también llamados arreglos o matrices) cuentan con muchos métodos. Para hacer las cosas más sencillas, en este capítulo los separamos en grupos.
 
 ## Agregar/remover ítems
 
@@ -62,7 +62,7 @@ alert( arr ); // ["Yo", "JavaScript"]
 
 ¿Fácil, no? Empezando desde el índice `1` removió `1` elemento.
 
-En el próximo ejemplo removemos 3 elementos y los reemplazamos con otros 2:
+En el próximo ejemplo, removemos 3 elementos y los reemplazamos con otros 2:
 
 ```js run
 let arr = [*!*"Yo", "estudio", "JavaScript",*/!* "ahora", "mismo"];
@@ -114,7 +114,7 @@ alert( arr ); // 1,2,3,4,5
 
 ### slice
 
-El método [arr.slice](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/slice) es mucho más simple que `arr.splice`.
+El método [arr.slice](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array/slice) es mucho más simple que su similar `arr.splice`.
 
 La sintaxis es:
 
@@ -124,7 +124,7 @@ arr.slice([principio], [final])
 
 Devuelve un nuevo array copiando en el mismo todos los elementos desde `principio` hasta `final` (sin incluir `final`). `principio` y `final` pueden ser negativos, en cuyo caso se asume la posición desde el final del array.
 
-Es similar al método para strings `str.slice`, pero en lugar de substrings genera subarrays.
+Es similar al método para strings `str.slice`, pero en lugar de substrings, genera subarrays.
 
 Por ejemplo:
 
@@ -206,7 +206,7 @@ El método [arr.forEach](https://developer.mozilla.org/es/docs/Web/JavaScript/Re
 La sintaxis:
 ```js
 arr.forEach(function(item, index, array) {
-  // ... hacer algo con el elemento
+  // ... hacer algo con un elemento
 });
 ```
 
@@ -274,7 +274,7 @@ const arr = [NaN];
 alert( arr.indexOf(NaN) ); // -1 (debería ser 0, pero la igualdad === no funciona para NaN)
 alert( arr.includes(NaN) );// true (correcto)
 ```
-Esto es porque `includes` fue agregado mucho después y usa un algoritmo interno de comparación actualizado.
+Esto es porque `includes` fue agregado a JavaScript mucho después, su algoritmo interno de comparación está actualizado.
 ````
 
 ### find y findIndex/findLastIndex
@@ -313,7 +313,7 @@ let user = users.find(item => item.id == 1);
 alert(user.name); // Celina
 ```
 
-En la vida real los arrays de objetos son bastante comunes por lo que el método `find` resulta muy útil.
+En la vida real, los arrays de objetos son bastante comunes, por lo que el método `find` resulta muy útil.
 
 Ten en cuenta que en el ejemplo anterior le pasamos a `find` la función `item => item.id == 1` con un argumento. Esto es lo más común, otros argumentos son raramente usados en esta función.
 
@@ -450,11 +450,11 @@ alert(arr);  // *!*1, 2, 15*/!*
 
 Ahora sí funciona como esperábamos.
 
-Detengámonos un momento y pensemos qué es lo que está pasando. El array `arr` puede ser un array de cualquier cosa, ¿no? Puede contener números, strings, objetos o lo que sea. Podemos decir que tenemos un conjunto de *ciertos items*. Para ordenarlos, necesitamos una *función de ordenamiento* que sepa cómo comparar los elementos. El orden por defecto es hacerlo como strings.
+Detengámonos a pensar, qué está pasando. El array `arr` puede ser un array de cualquier cosa, ¿verdad? Puede contener números, strings, objetos o lo que sea. Podemos decir que tenemos un conjunto de *ciertos items*. Para ordenarlos, necesitamos una *función de ordenamiento* que sepa cómo comparar los elementos. El orden predeterminado es hacerlo como strings.
 
 El método `arr.sort(fn)` implementa un algoritmo genérico de orden. No necesitamos preocuparnos de cómo funciona internamente (la mayoría de las veces es una forma optimizada del algoritmo [quicksort](https://es.wikipedia.org/wiki/Quicksort) o [Timsort](https://en.wikipedia.org/wiki/Timsort)). Este método va a recorrer el array, comparar sus elementos usando la función dada y, finalmente, reordenarlos. Todo los que necesitamos hacer es proveer la `fn` que realiza la comparación.
 
-Por cierto, si queremos saber qué elementos son comparados, nada nos impide ejecutar alert() en ellos:
+Por cierto, si queremos ver qué elementos están siendo comparados, nada nos impide mostrarlos en un alert():
 
 ```js run
 [1, -2, 15, 2, 0, 8].sort(function(a, b) {
@@ -595,7 +595,7 @@ Argumentos:
 
 Mientras la función sea llamada, el resultado del llamado anterior se pasa al siguiente como primer argumento.
 
-Entonces, el primer argumento es el acumulador que almacena el resultado combinado de todas las veces anteriores en que se ejecutó, y al final se convierte en el resultado de `reduce`.
+Entonces, el primer argumento es un acumulador que almacena el resultado combinado de todas las ejecuciones previas, y al final se convierte en el resultado de `reduce`.
 
 ¿Suena complicado?
 
@@ -749,9 +749,9 @@ Veamos el ayudamemoria de métodos para arrays:
   - `concat(...items)` -- devuelve un nuevo array: copia todos los elementos del array actual y le agrega `items`. Si alguno de los `items` es un array, se toman sus elementos.
 
 - Para buscar entre elementos:
-  - `indexOf/lastIndexOf(item, pos)` -- busca por `item` comenzando desde la posición `pos`, devolviendo el índice o `-1` si no se encuentra.
-  - `includes(value)` -- devuelve `true` si el array tiene `value`, si no `false`.
-  - `find/filter(func)` -- filtra elementos a través de la función, devuelve el primer/todos los valores que devuelven `true`.
+  - `indexOf/lastIndexOf(item, pos)` -- busca por `item` comenzando desde la posición `pos` y devuelve su índice, o `-1` si no lo encuentra.
+  - `includes(value)` -- devuelve `true` si el array contiene `value`, o `false` en caso contrario.
+  - `find/filter(func)` -- filtra elementos a través de 'func', devuelve el primero/todos los valores que devolvieron `true`.
   - `findIndex` es similar a  `find`, pero devuelve el índice en lugar del valor.
 
 - Para iterar sobre elementos:
@@ -796,7 +796,7 @@ Podemos usar `every` para comparar arrays:
 
 Para la lista completa, ver [manual](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Array).
 
-A primera vista puede parecer que hay demasiados métodos para aprender y un tanto difíciles de recordar. Pero con el tiempo se vuelve más fácil.
+A primera vista puede parecer que hay demasiados métodos y difíciles de recordar. En realidad es mucho más fácil de lo que se ve.
 
 Revisa el ayudamemoria para conocerlos. Después realiza las prácticas de este capítulo para ganar experiencia con los métodos para arrays.
 
diff --git a/1-js/05-data-types/07-map-set/article.md b/1-js/05-data-types/07-map-set/article.md
index 6215fcc50..d74b0bca8 100644
--- a/1-js/05-data-types/07-map-set/article.md
+++ b/1-js/05-data-types/07-map-set/article.md
@@ -3,8 +3,8 @@
 
 Hasta este momento, hemos aprendido sobre las siguientes estructuras de datos:
 
-- Objetos para almacenar colecciones de datos ordenadas mediante una clave.
-- Arrays para almacenar colecciones ordenadas de datos.
+- Objetos, para almacenar colecciones de datos accesibles a través de una clave.
+- Arrays, para almacenar colecciones ordenadas de datos.
 
 Pero eso no es suficiente para la vida real. Por eso también existen `Map` y `Set`.
 
@@ -19,8 +19,8 @@ Los métodos y propiedades son:
 - [`map.get(clave)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- devuelve el valor de la clave. Será `undefined` si la `clave` no existe en map.
 - [`map.has(clave)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has) -- devuelve `true` si la `clave` existe en map, `false` si no existe.
 - [`map.delete(clave)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- elimina el elemento con esa clave.
-- [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- elimina todo de map.
-- [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- tamaño, devuelve la cantidad actual de elementos.
+- [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- elimina todo del map.
+- [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- tamaño, devuelve la cantidad de elementos actual.
 
 Por ejemplo:
 
@@ -134,7 +134,7 @@ for (let entry of recipeMap) { // lo mismo que recipeMap.entries()
 ```
 
 ```smart header="Se utiliza el orden de inserción."
-La iteración va en el mismo orden en que se insertaron los valores. `Map` conserva este orden, a diferencia de un `Objeto` normal.
+La iteración va en el mismo orden en que se insertaron los valores. `Map` conserva este orden, a diferencia de un `Objet` normal.
 ```
 
 Además, `Map` tiene un método `forEach` incorporado, similar al de `Array`:
diff --git a/1-js/05-data-types/10-destructuring-assignment/article.md b/1-js/05-data-types/10-destructuring-assignment/article.md
index 1506089fc..ca141a835 100644
--- a/1-js/05-data-types/10-destructuring-assignment/article.md
+++ b/1-js/05-data-types/10-destructuring-assignment/article.md
@@ -5,9 +5,9 @@ Las dos estructuras de datos más usadas en JavaScript son `Object` y `Array`.
 - Los objetos nos permiten crear una simple entidad que almacena items con una clave cada uno.
 - los arrays nos permiten reunir items en una lista ordenada.
 
-Pero cuando los pasamos a una función, tal vez no necesitemos un objeto o array como un conjunto sino en piezas individuales.
+Pero cuando los pasamos a una función, tal vez no necesitemos el objeto o array completo. La función podría requerir solamente ciertos elementos o propiedades.
 
-La *asignación desestructurante* es una sintaxis especial que nos permite "desempaquetar" arrays u objetos en varias variables, porque a veces es más conveniente. 
+La *asignación desestructurante* es una sintaxis especial que nos permite "desempaquetar" arrays u objetos en un manojo de variables, porque a veces es lo más conveniente. 
 
 La desestructuración también funciona bien con funciones complejas que tienen muchos argumentos, valores por defecto, etcétera. Pronto lo veremos.
 
@@ -16,7 +16,7 @@ La desestructuración también funciona bien con funciones complejas que tienen
 Un ejemplo de cómo el array es desestructurado en variables:
 
 ```js
-// tenemos un array con el nombre y apellido
+// tenemos un array con un nombre y apellido
 let arr = ["John", "Smith"]
 
 *!*
@@ -43,7 +43,7 @@ alert(surname);  // Smith
 Como puedes ver, la sintaxis es simple. Aunque hay varios detalles peculiares. Veamos más ejemplos para entenderlo mejor.
 
 ````smart header="\"Desestructuración\" no significa \"destructivo\"."
-Se llama "asignación desestructurante" porque "desestructura" al copiar elementos dentro de variables, pero el array en sí no es modificado.
+Se llama "asignación desestructurante" porque "desestructura" al copiar elementos dentro de variables. Sin embargo, el array en sí no es modificado.
 
 Es sólo una manera más simple de escribir:
 ```js
@@ -187,7 +187,7 @@ let [name1, name2, *!*...titles*/!*] = ["Julius", "Caesar", "Consul", "of the Ro
 
 ### Valores predeterminados
 
-Si el array es más corto que la lista de variables a la izquierda, no habrá errores. Los valores ausentes son considerados undefined:
+Si el array es más corto que la lista de variables de la izquierda, no habrá errores. Los valores ausentes quedan `undefined`:
 
 ```js run
 *!*
@@ -418,7 +418,7 @@ alert( title ); // Menu
 
 ## Desestructuración anidada
 
-Si un objeto o array contiene objetos y arrays anidados, podemos utilizar patrones del lado izquierdo más complejos para extraer porciones más profundas.
+Si un objeto o array contiene otros objetos y arrays anidados, podemos utilizar patrones más complejos en el lado izquierdo para extraer porciones más profundas.
 
 En el código de abajo `options` tiene otro objeto en la propiedad `size` y un array en la propiedad `items`. El patrón en el lado izquierdo de la asignación tiene la misma estructura para extraer valores de ellos:
 
@@ -449,19 +449,19 @@ alert(item1);  // Cake
 alert(item2);  // Donut
 ```
 
-Todas las propiedades del objeto `options` con excepción de `extra` que no está en el lado izquierda, son asignadas a las variables correspondientes:
+Todas las propiedades del objeto `options`, con excepción de `extra` que no está en el lado izquierdo, son asignadas a las variables correspondientes:
 
 ![](destructuring-complex.svg)
 
 Por último tenemos `width`, `height`, `item1`, `item2` y `title` desde el valor predeterminado.
 
-Tenga en cuenta que no hay variables para `size` e `items`, ya que tomamos su contenido en su lugar.
+Nota que no hay variables para `size` e `items`, ya que tomamos su contenido en su lugar.
 
 ## Argumentos de función inteligentes
 
-Hay momentos en que una función tiene muchos argumentos, la mayoría de los cuales son opcionales. Eso es especialmente cierto para las interfaces de usuario. Imagine una función que crea un menú. Puede tener ancho, altura, título, elementos de lista, etcétera.
+Hay momentos en que una función tiene muchos parámetros, la mayoría de los cuales son opcionales. Eso es especialmente cierto para las interfaces de usuario. Imagine una función que crea un menú. Puede tener ancho, altura, título, elementos de lista, etcétera.
 
-Aquí hay una forma errónea de escribir tal función:
+Esta es una forma incorrecta de escribir tal función:
 
 ```js
 function showMenu(title = "Untitled", width = 200, height = 100, items = []) {
@@ -469,7 +469,7 @@ function showMenu(title = "Untitled", width = 200, height = 100, items = []) {
 }
 ```
 
-En la vida real, el problema es cómo recordar el orden de los argumentos. Normalmente los IDEs (Entorno de desarrollo integrado) intentan ayudarnos, especialmente si el código está bien documentado, pero aún así... Otro problema es cómo llamar a una función si queremos que use sus valores predeterminados en la mayoría de los argumentos.
+En la vida real, el problema es cómo recordar el orden de los argumentos. Normalmente los IDEs ayudan, especialmente si el código está bien documentado, pero aún así... Otro problema es cómo llamar a una función si queremos que la mayoría de los argumentos usen sus valores predeterminados.
 
 ¿Así?
 
@@ -561,7 +561,7 @@ En el código de arriba, todo el objeto de argumentos es `{}` por defecto, por l
 - La asignación desestructurante permite mapear instantáneamente un objeto o array en varias variables.
 - La sintaxis completa para objeto:
     ```js
-    let {prop : varName = default, ...rest} = object
+    let {prop : varName = defaultValue, ...rest} = object
     ```
 
     Esto significa que la propiedad `prop` se asigna a la variable `varName`; pero si no existe tal propiedad, se usa el valor `default`.
diff --git a/1-js/05-data-types/12-json/article.md b/1-js/05-data-types/12-json/article.md
index e18beef90..0a449bbfe 100644
--- a/1-js/05-data-types/12-json/article.md
+++ b/1-js/05-data-types/12-json/article.md
@@ -405,7 +405,7 @@ Para decodificar un string JSON, necesitamos otro método llamado [JSON.parse](h
 
 La sintaxis:
 ```js
-let value = JSON.parse(str, [reviver]);
+let value = JSON.parse(str[, reviver]);
 ```
 
 str
diff --git a/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md b/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md
index bf079db40..f8ea2b9b2 100644
--- a/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md
+++ b/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md
@@ -1,7 +1,7 @@
 
-El error se produce porque `ask` obtiene las funciones `loginOk/loginFail` sin el objeto.
+El error se produce porque `askPassword` obtiene las funciones `loginOk/loginFail` sin el objeto.
 
-Cuando los llama, asumen naturalmente `this = undefined`.
+Cuando las llama, estas asumen `this = undefined`.
 
 Vamos a usar `bind` para enlazar el contexto:
 
@@ -39,9 +39,6 @@ askPassword(() => user.loginOk(), () => user.loginFail());
 ```
 
 
-Por lo general, eso también funciona y se ve bien.
+En general, funciona y se ve bien.
 
-Aunque es un poco menos confiable en situaciones más complejas donde la variable `user` podría cambiar *después* de que se llama a `askPassword`, *antes* de que el visitante responde y llame a `() => user.loginOk ()`.
-
-
-It's a bit less reliable though in more complex situations where `user` variable might change *after* `askPassword` is called, but *before* the visitor answers and calls `() => user.loginOk()`. 
+Aunque esto es menos confiable, si puede darse el caso en donde `user` cambia después de llamar a `askPassword`, pero antes de que el visitante responda y se invoque `() => user.loginOk()`.
diff --git a/1-js/06-advanced-functions/10-bind/article.md b/1-js/06-advanced-functions/10-bind/article.md
index 7226b19a8..6f666096b 100644
--- a/1-js/06-advanced-functions/10-bind/article.md
+++ b/1-js/06-advanced-functions/10-bind/article.md
@@ -125,7 +125,7 @@ funcUser(); // John
 */!*
 ```
 
-Aquí `func.bind(user)` es como una "variante vinculada" de `func`, con `this = user` fijo en ella.
+Aquí `func.bind(user)` es una "variante vinculada" de `func`, con `this = user` fijo en ella.
 
 Todos los argumentos se pasan al `func` original "tal cual", por ejemplo:
 
diff --git a/1-js/07-object-properties/01-property-descriptors/article.md b/1-js/07-object-properties/01-property-descriptors/article.md
index 543f2a63f..d48f86fc2 100644
--- a/1-js/07-object-properties/01-property-descriptors/article.md
+++ b/1-js/07-object-properties/01-property-descriptors/article.md
@@ -259,7 +259,7 @@ Object.defineProperty(user, "name", {
   configurable: false
 });
 
-// No seremos capaces de cambiar usuario.nombre o sus identificadores
+// No seremos capaces de cambiar user.name o sus identificadores
 // Nada de esto funcionará:
 user.name = "Pedro";
 delete user.name;
diff --git a/1-js/07-object-properties/02-property-accessors/article.md b/1-js/07-object-properties/02-property-accessors/article.md
index f5b5b588a..9a76b6f9c 100644
--- a/1-js/07-object-properties/02-property-accessors/article.md
+++ b/1-js/07-object-properties/02-property-accessors/article.md
@@ -181,7 +181,7 @@ user.name = ""; // El nombre es demasiado corto...
 
 Entonces, el nombre es almacenado en la propiedad `_name`, y el acceso se hace a través de getter y setter.
 
-Técnicamente, el código externo todavía puede acceder al nombre directamente usando "usuario._nombre". Pero hay un acuerdo ampliamente conocido de que las propiedades que comienzan con un guión bajo "_" son internas y no deben ser manipuladas desde el exterior del objeto.
+Técnicamente, el código externo todavía puede acceder al nombre directamente usando `user._name`. Pero hay un acuerdo ampliamente conocido de que las propiedades que comienzan con un guión bajo `"_"` son internas y no deben ser manipuladas desde el exterior del objeto.
 
 
 ## Uso para compatibilidad
diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md
index b2bb4d07e..d6cc0c071 100644
--- a/1-js/08-prototypes/04-prototype-methods/article.md
+++ b/1-js/08-prototypes/04-prototype-methods/article.md
@@ -14,7 +14,7 @@ El único uso de `__proto__` que no está mal visto, es como una propiedad cuand
 
 Aunque hay un método especial para esto también:
 
-- [Object.create(proto, [descriptors])](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/create) -- crea un objeto vacío con el "proto" dado como `[[Prototype]]` y descriptores de propiedad opcionales.
+- [Object.create(proto[, descriptors])](https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/create) -- crea un objeto vacío con el `proto` dado como `[[Prototype]]` y descriptores de propiedad opcionales.
 
 Por ejemplo:
 
@@ -116,7 +116,7 @@ alert(obj[key]); // [object Object], no es "algún valor"!
 
 Aquí, si el usuario escribe en `__proto__`, ¡la asignación en la línea 4 es ignorada!
 
-Eso no debería sorprendernos. La propiedad `__proto__` es especial: debe ser un objeto o `null`. Una cadena no puede convertirse en un prototipo. Es por ello que la asignación de un string a `__proto__` es ignorada.
+Esto no debe sorprendernos. La propiedad `__proto__` es especial: debe ser o un objeto o `null`. Una cadena no puede convertirse en un prototipo. Es por ello que la asignación de un string a `__proto__` es ignorada.
 
 Pero no *intentamos* implementar tal comportamiento, ¿verdad? Queremos almacenar pares clave/valor, y la clave llamada `"__proto__"` no se guardó correctamente. Entonces, ¡eso es un error!
 
diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md
index a53a7f957..27064f179 100644
--- a/1-js/10-error-handling/1-try-catch/article.md
+++ b/1-js/10-error-handling/1-try-catch/article.md
@@ -632,7 +632,7 @@ Por ejemplo:
 
 El rol del controlador global `window.onerror` generalmente no es recuperar la ejecución del script, probablemente sea imposible en caso de errores de programación, pero sí enviar el mensaje de error a los desarrolladores.
 
-También hay servicios web que proporcionan registro de errores para tales casos, como <https://errorception.com> o <https://www.muscula.com>.
+También hay servicios web que proporcionan registro de errores para tales casos, como <https://muscula.com> o <https://www.sentry.io>.
 
 Estos servicios funcionan así:
 
diff --git a/1-js/11-async/02-promise-basics/article.md b/1-js/11-async/02-promise-basics/article.md
index 1b30c4e8e..c5c18b708 100644
--- a/1-js/11-async/02-promise-basics/article.md
+++ b/1-js/11-async/02-promise-basics/article.md
@@ -46,7 +46,7 @@ Más adelante veremos cómo los "fanáticos" pueden suscribirse a estos cambios.
 
 Aquí hay un ejemplo de un constructor de promesas y una función ejecutora simple con "código productor" que toma tiempo (a través de `setTimeout`):
 
-```js run
+```js 
 let promise = new Promise(function(resolve, reject) {
   // la función se ejecuta automáticamente cuando se construye la promesa
 
@@ -214,15 +214,15 @@ La llamada `.catch(f)` es completamente equivalente a `.then(null, f)`, es solo
 
 ## Limpieza: finally
 
-Al igual que hay una cláusula `finally` en un `try {...} catch {...}` normal, hay un `finally` en las promesas.
+Al igual que en un `try {...} catch {...}`, las promesas también tienen la cláusula `finally`.
 
-La llamada `.finally(f)` es similar a `.then(f, f)` en el sentido de que `f` siempre se ejecuta cuando se resuelve la promesa: ya sea que se resuelva o rechace.
+La llamada `.finally(f)` es similar a `.then(f, f)`, ya que garantiza que `f` se ejecute siempre, sin importar si la promesa se resuelve o rechaza.
 
-La idea de `finally` es establecer un manejador para realizar la limpieza y finalización después de que las operaciones se hubieran completado.
+La idea de `finally` es definir un manejador para realizar tareas de limpieza y finalización una vez que la operacióm haya concluido.
 
-Por ejemplo, detener indicadores de carga, cerrar conexiones que ya no son necesarias, etc.
+Por ejemplo, detener indicadores de carga, cerrar conexiones innecesarias, etc.
 
-Puedes pensarlo como el finalizador de la fiesta. No importa si la fiesta fue buena o mala ni cuántos invitados hubo, aún necesitamos (o al menos deberíamos) hacer la limpieza después.
+Puedes pensarlo como el momento de la limpieza después de la fiesta. No importa si fue un éxito o un fracaso ni cuántos invitados hubo, siempre hay que limpiar.
 
 El código puede verse como esto:
 
@@ -238,14 +238,14 @@ new Promise((resolve, reject) => {
   .then(result => show result, err => show error)
 ```
 
-Sin embargo, note que `finally(f) no es exactamente un alias de `then(f, f)`.
+Sin embargo, note que `finally(f) no equivale exactamente a `then(f, f)`.
 
 Hay diferencias importantes:
 `
-1. Un manejador `finally` no tiene argumentos. En `finally` no sabemos si la promesa es exitosa o no. Eso está bien, ya que usualmente nuestra tarea es realizar procedimientos de finalización "generales".
+1. Un manejador `finally` no tiene argumentos. En `finally` no sabemos si la promesa se resolvió o rechazó. Eso es intencional, ya que su propósito es realizar procedimientos de finalización generales.
 
-    Observa el ejemplo anterior: como puedes ver, el manejador de `finally` no tiene argumentos, y lo que sale de la promesa es manejado en el siguiente manejador.
-2. Resultados y errores pasan "a través" del manejador de `finally`. Estos pasan al siguiente manejador que se adecúe.
+    Observa el ejemplo anterior: como puedes ver, el manejador `finally` no recibe argumentos, y el resultado de la promesa es manejado en el siguiente `then`.
+2. Los resultados y errores pasan a través de `finally` sin modificación. Estos pasan al siguiente manejador adecuado.
 
     Por ejemplo, aquí el resultado se pasa a través de `finally` al `then` que le sigue:
     ```js run
diff --git a/1-js/11-async/08-async-await/04-promise-all-failure/solution.md b/1-js/11-async/08-async-await/04-promise-all-failure/solution.md
new file mode 100644
index 000000000..9fda8e000
--- /dev/null
+++ b/1-js/11-async/08-async-await/04-promise-all-failure/solution.md
@@ -0,0 +1,113 @@
+
+The root of the problem is that `Promise.all` immediately rejects when one of its promises rejects, but it do nothing to cancel the other promises.
+
+In our case, the second query fails, so `Promise.all` rejects, and the `try...catch` block catches this error.Meanwhile, other promises are *not affected* - they independently continue their execution. In our case, the third query throws an error of its own after a bit of time. And that error is never caught, we can see it in the console.
+
+The problem is especially dangerous in server-side environments, such as Node.js, when an uncaught error may cause the process to crash.
+
+How to fix it?
+
+An ideal solution would be to cancel all unfinished queries when one of them fails. This way we avoid any potential errors.
+
+However, the bad news is that service calls (such as `database.query`) are often implemented by a 3rd-party library which doesn't support cancellation. Then there's no way to cancel a call.
+
+As an alternative, we can write our own wrapper function around `Promise.all` which adds a custom `then/catch` handler to each promise to track them: results are gathered and, if an error occurs, all subsequent promises are ignored.
+
+```js
+function customPromiseAll(promises) {
+  return new Promise((resolve, reject) => {
+    const results = [];
+    let resultsCount = 0;
+    let hasError = false; // we'll set it to true upon first error
+
+    promises.forEach((promise, index) => {
+      promise
+        .then(result => {
+          if (hasError) return; // ignore the promise if already errored
+          results[index] = result;
+          resultsCount++;
+          if (resultsCount === promises.length) {
+            resolve(results); // when all results are ready - successs
+          }
+        })
+        .catch(error => {
+          if (hasError) return; // ignore the promise if already errored
+          hasError = true; // wops, error!
+          reject(error); // fail with rejection
+        });
+    });
+  });
+}
+```
+
+This approach has an issue of its own - it's often undesirable to `disconnect()` when queries are still in the process.
+
+It may be important that all queries complete, especially if some of them make important updates.
+
+So we should wait until all promises are settled before going further with the execution and eventually disconnecting.
+
+Here's another implementation. It behaves similar to `Promise.all` - also resolves with the first error, but waits until all promises are settled.
+
+```js
+function customPromiseAllWait(promises) {
+  return new Promise((resolve, reject) => {
+    const results = new Array(promises.length);
+    let settledCount = 0;
+    let firstError = null;
+
+    promises.forEach((promise, index) => {
+      Promise.resolve(promise)
+        .then(result => {
+          results[index] = result;
+        })
+        .catch(error => {
+          if (firstError === null) {
+            firstError = error;
+          }
+        })
+        .finally(() => {
+          settledCount++;
+          if (settledCount === promises.length) {
+            if (firstError !== null) {
+              reject(firstError);
+            } else {
+              resolve(results);
+            }
+          }
+        });
+    });
+  });
+}
+```
+
+Now `await customPromiseAllWait(...)` will stall the execution until all queries are processed.
+
+This is a more reliable approach, as it guarantees a predictable execution flow.
+
+Lastly, if we'd like to process all errors, we can use either use `Promise.allSettled` or write a wrapper around it to gathers all errors in a single [AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) object and rejects with it.
+
+```js
+// wait for all promises to settle
+// return results if no errors
+// throw AggregateError with all errors if any
+function allOrAggregateError(promises) {
+  return Promise.allSettled(promises).then(results => {
+    const errors = [];
+    const values = [];
+
+    results.forEach((res, i) => {
+      if (res.status === 'fulfilled') {
+        values[i] = res.value;
+      } else {
+        errors.push(res.reason);
+      }
+    });
+
+    if (errors.length > 0) {
+      throw new AggregateError(errors, 'One or more promises failed');
+    }
+
+    return values;
+  });
+}
+```
diff --git a/1-js/11-async/08-async-await/04-promise-all-failure/task.md b/1-js/11-async/08-async-await/04-promise-all-failure/task.md
new file mode 100644
index 000000000..74571c43e
--- /dev/null
+++ b/1-js/11-async/08-async-await/04-promise-all-failure/task.md
@@ -0,0 +1,79 @@
+
+# Dangerous Promise.all
+
+`Promise.all` is a great way to parallelize multiple operations. It's especially useful when we need to make parallel requests to multiple services.
+
+However, there's a hidden danger. We'll see an example in this task and explore how to avoid it.
+
+Let's say we have a connection to a remote service, such as a database.
+
+There're two functions: `connect()` and `disconnect()`.
+
+When connected, we can send requests using `database.query(...)` - an async function which usually returns the result but also may throw an error.
+
+Here's a simple implementation:
+
+```js
+let database;
+
+function connect() {
+  database = {
+    async query(isOk) {
+      if (!isOk) throw new Error('Query failed');
+    }
+  };
+}
+
+function disconnect() {
+  database = null;
+}
+
+// intended usage:
+// connect()
+// ...
+// database.query(true) to emulate a successful call
+// database.query(false) to emulate a failed call
+// ...
+// disconnect()
+```
+
+Now here's the problem.
+
+We wrote the code to connect and send 3 queries in parallel (all of them take different time, e.g. 100, 200 and 300ms), then disconnect:
+
+```js
+// Helper function to call async function `fn` after `ms` milliseconds
+function delay(fn, ms) {
+  return new Promise((resolve, reject) => {
+    setTimeout(() => fn().then(resolve, reject), ms);
+  });
+}
+
+async function run() {
+  connect();
+
+  try {
+    await Promise.all([
+      // these 3 parallel jobs take different time: 100, 200 and 300 ms
+      // we use the `delay` helper to achieve this effect
+*!*
+      delay(() => database.query(true), 100),
+      delay(() => database.query(false), 200),
+      delay(() => database.query(false), 300)
+*/!*
+    ]);
+  } catch(error) {
+    console.log('Error handled (or was it?)');
+  }
+
+  disconnect();
+}
+
+run();
+```
+
+Two of these queries happen to be unsuccessful, but we're smart enough to wrap the `Promise.all` call into a `try..catch` block.
+
+However, this doesn't help! This script actually leads to an uncaught error in console!
+
+Why? How to avoid it?
\ No newline at end of file
diff --git a/1-js/13-modules/02-import-export/article.md b/1-js/13-modules/02-import-export/article.md
index 8147746e2..91ff2b848 100644
--- a/1-js/13-modules/02-import-export/article.md
+++ b/1-js/13-modules/02-import-export/article.md
@@ -96,10 +96,10 @@ Pues hay algunas razones.
 1. Listar explícitamente qué importar da nombres más cortos: `sayHi()` en lugar de `say.sayHi()`.
 2. La lista explícita de importaciones ofrece una mejor visión general de la estructura del código: qué se usa y dónde. Facilita el soporte de código y la refactorización.
 
-```smart header="No temas importar demasiado"
-Las herramientas de empaquetado modernas, como [webpack](https://webpack.js.org/) y otras, construyen los módulos juntos y optimizan la velocidad de carga. También eliminan las importaciones no usadas.
+```smart header="No temas hacer demasiados import"
+Las herramientas de empaquetado modernas, como [webpack](https://webpack.js.org/) y otras, unen los módulos, optimizan la velocidad de carga, y eliminan las importaciones no usadas.
 
-Por ejemplo, si importas `import * as library` desde una librería de código enorme, y usas solo unos pocos métodos, los que no se usen [no son incluidos](https://github.com/webpack/webpack/tree/main/examples/harmony-unused#examplejs) en el paquete optimizado.
+Por ejemplo, si importas `import * as library` desde una librería de código enorme, y usas solo unos pocos métodos, los que no se usen [no serán incluidos](https://github.com/webpack/webpack/tree/main/examples/harmony-unused#examplejs) en el paquete optimizado.
 ```
 
 ## Importar "as"
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/article.md b/1-js/99-js-misc/07-weakref-finalizationregistry/article.md
new file mode 100644
index 000000000..492923908
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/article.md
@@ -0,0 +1,483 @@
+
+# WeakRef y FinalizationRegistry
+
+```warn header="Características \"ocultas\" del lenguaje"
+Este artículo trata un tema muy específico que la mayoría de los desarrolladores rara vez encuentran en la práctica, e incluso pueden desconocer su existencia.
+
+Si recién estás aprendiendo JavaScript, te recomendamos saltar este capítulo.  
+```
+
+El *principio de alcance*, explicado en el capítulo <info:garbage-collection>,
+establece que el motor de JavaScript garantiza que se mantengan en memoria los valores mientras sean accesibles o estén en uso.
+
+Por ejemplo:
+
+
+```js
+//  la variable user mantiene una referencia fuerte al objeto 
+let user = { name: "John" };
+
+// sobrescribimos el valor de la variable user 
+user = null;
+
+// la referencia se pierde y el objeto será eliminado de la memoria
+
+```
+
+Compliquemos un poco el código con dos referencias fuertes:
+
+```js
+//  la variable user mantiene una referencia fuerte al objeto 
+let user = { name: "John" };
+
+// copiamos la referencia fuerte al objeto en la variable admin
+*!*
+let admin = user;
+*/!*
+
+// sobrescribimos el valor de la variable user
+user = null;
+
+// el objeto sigue siendo accesible a través de la variable admin 
+```
+El objeto `{ name: "John" }` solo se eliminará de la memoria si no quedan referencias fuertes a él; es decir, si también sobrescribimos la variable `admin`.
+
+En JavaScript existe un concepto llamado `WeakRef`, o referencia débil, que se comporta de manera diferente.
+
+
+````smart header="Términos: \"Referencia fuerte\", \"Referencia débil\""
+**Referencia fuerte** -- es una referencia a un objeto o valor que impide que el recolector de basura lo elimine, manteniéndolo en memoria.
+
+Esto significa que el objeto o valor permanecerá en memoria y no será eliminado por el recolector de basura mientras haya referencias fuertes activas a él.
+
+En JavaScript, las referencias típicas son fuertes. Por ejemplo:
+
+```js
+//  la variable user mantiene una referencia fuerte al objeto
+let user = { name: "John" };
+```
+**Referencia débil** -- es una referencia a un objeto o valor que *no* impide que sean eliminados por el recolector de basura.
+Un objeto o valor puede ser borrado por el recolector de basura si las únicas referencias a él son débiles.
+````
+
+## WeakRef
+
+
+````warn header="Advertencia"
+Antes de profundizar en el tema, es importante señalar que su uso requiere una planificación cuidadosa y que, en general, es mejor evitarlas si no son estrictamente necesarias.
+````
+
+`WeakRef` -- es un objeto que mantiene referencias débiles a otros objetos, llamados objetivo (`target`) o referente (`referent`).
+
+La particularidad de `WeakRef` es que no impide que el recolector de basura elimine a su "referente". En otras palabras, un objeto `WeakRef` no mantiene vivo al objeto referido.
+
+Ahora tomemos la variable `user` como "referente" y establezcamos una referencia débil hacia ella en la variable `admin`.
+Para crear una referencia débil se debe usar el constructor `WeakRef`, pasando como argumento el objetivo (el objeto al que queremos hacer la referencia débil).
+
+En nuestro caso, ese objeto es la variable `user`:
+
+
+```js
+//  la variable user mantiene una referencia fuerte al objeto
+let user = { name: "John" };
+
+//  la variable admin mantiene una referencia débil al objeto
+*!*
+let admin = new WeakRef(user);
+*/!*
+
+```
+
+El siguiente diagrama muestra los dos tipos de referencia: una referencia fuerte con la variable `user` y una referencia débil con la variable `admin`:
+
+![](weakref-finalizationregistry-01.svg)
+
+Luego, en algún momento, dejamos de usar la variable `user` (su valor se sobrescribe, sale de alcance, etc.), pero la instancia de `WeakRef` sigue almacenada en la variable `admin`:
+
+```js
+// sobrescribimos el valor de la variable user
+user = null;
+```
+
+Una referencia débil a un objeto no es suficiente para mantenerlo "vivo". Si las únicas referencias restantes a un objeto referido son débiles, el recolector de basura puede destruirlo y reutilizar su memoria para otra cosa.
+
+Sin embargo, hasta que el objeto sea realmente eliminado, la referencia débil puede seguir devolviéndolo, incluso si ya no existen referencias fuertes hacia él.
+Es decir, nuestro objeto se convierte en una especie de "gato de Schrödinger": no podemos saber con certeza si está "vivo" o "muerto".
+
+![](weakref-finalizationregistry-02.svg)
+
+En este punto, para obtener el objeto desde la instancia de `WeakRef`, usamos su método `deref()`.
+
+El método `deref()` devuelve el objeto referido al que apunta el `WeakRef`, si aún está en memoria. Si el objeto ha sido eliminado por el recolector de basura,`deref()` devolverá `undefined`:
+
+
+```js
+let ref = admin.deref();
+
+if (ref) {
+  // el objeto sigue accesible: podemos manipularlo libremente
+} else {
+  // el objeto ha sido eliminado por el recolector de basura
+}
+```
+
+## WeakRef, casos de uso
+
+`WeakRef` se usa típicamente para crear cachés o [arrays asociativos](https://es.wikipedia.org/wiki/Tabla_hash) que almacenan objetos con un alto consumo de recursos.
+Esto permite evitar que dichos objetos permanezcan en memoria solo por estar en la caché o en un array asociativo..  
+
+Uno de los principales ejemplos es cuando manejamos múltiples objetos de imagen binaria (por ejemplo, representados como `ArrayBuffer` o `Blob`), y queremos asociarles un nombre o una ruta.
+Las estructuras de datos existentes no son del todo adecuadas para esto:
+
+- Usar  `Map` para asociar nombres con imágenes (o viceversa) mantiene las imágenes en memoria, ya que siguen presentes en el `Map` como claves o valores.
+- `WeakMap` tampoco es una opción válida: los objetos usados como claves en `WeakMap` tienen referencias débiles, por lo que el recolector de basura puede eliminarlos.
+
+En este caso, necesitamos una estructura de datos que use referencias débiles en sus valores.
+
+Para ello, podemos usar una colección `Map`, donde los valores sean instancias de `WeakRef` apuntando a los objetos grandes que queremos manejar.
+Así, evitamos mantener estos objetos grandes e innecesarios en memoria más tiempo del necesario.  
+
+De este modo, si el objeto aún es accesible, podemos obtenerlo desde la caché.
+Si ha sido eliminado por el recolector de basura, lo regeneramos o lo descargamos nuevamente.  
+
+Esto permite reducir el uso de memoria en ciertas situaciones.  
+
+## Ejemplo №1: Uso de WeakRef para caché
+
+A continuación, se muestra un fragmento de código que demuestra el uso de `WeakRef`.  
+
+En resumen, utilizamos un `Map` con claves de tipo string y objetos `WeakRef` como valores.
+Si el objeto referenciado por `WeakRef` no ha sido eliminado por el recolector de basura, lo recuperamos de la caché.
+Caso contrario, lo descargamos nuevamente y lo almacenamos en la caché para su posible reutilización:  
+
+```js
+function fetchImg() {
+    // función abstracta para descargar imágenes...
+}
+
+function weakRefCache(fetchImg) { // (1)
+    const imgCache = new Map(); // (2)
+
+    return (imgName) => { // (3)
+        const cachedImg = imgCache.get(imgName); // (4)
+
+        if (cachedImg?.deref()) { // (5)
+            return cachedImg?.deref();
+        }
+
+        const newImg = fetchImg(imgName); // (6)
+        imgCache.set(imgName, new WeakRef(newImg)); // (7)
+
+        return newImg;
+    };
+}
+
+const getCachedImg = weakRefCache(fetchImg);
+```
+
+Analicemos en detalle lo que ocurre aquí:
+1. `weakRefCache` -- es una función de orden superior que recibe otra función, `fetchImg`, como argumento. En este ejemplo, no es necesario describir `fetchImg` en detalle, ya que puede ser cualquier lógica para descargar imágenes.
+2. `imgCache` -- es una caché de imágenes que almacena los resultados de `fetchImg` en un `map`, con claves de tipo `string` para los nombres de las imágenes y objetos `WeakRef` como valores.
+3. Se devuelve una función anónima que toma el nombre de la imagen como argumento. Este argumento se usa como clave en la caché.
+4. Se intenta obtener el resultado almacenado en caché usando la clave proporcionada.
+5. Si la caché contiene un valor para la clave especificada y el objeto referenciado por `WeakRef` aún existe, se devuelve el resultado en caché.
+6. Si no hay una entrada en la caché con la clave solicitada, o si `deref()` devuelve `undefined` (lo que significa que el objeto ha sido eliminado por el recolector de basura), se vuelve a descargar la imagen con `fetchImg`.
+7. La imagen descargada se almacena en la caché como un objeto `WeakRef`. 
+
+Ahora tenemos una colección `Map`donde las claves son string con los nombres de imágenes y los valores son objetos `WeakRef` que contienen las imágenes.
+
+Esta técnica ayuda a evitar la asignación innecesaria de grandes cantidades de memoria a objetos que ya no están en uso.
+Pero también ahorra memoria y tiempo cuando se reutilizan objetos en caché.  
+
+Aquí hay una representación visual de este código:  
+
+![](weakref-finalizationregistry-03.svg)
+
+Sin embargo, esta implementación tiene una desventaja: con el tiempo, `Map` se llenará de claves `string` que apuntan a `WeakRef` cuyos objetos referenciados ya han sido eliminados por el recolector de basura:  
+
+![](weakref-finalizationregistry-04.svg)
+
+Una forma de manejar este problema es limpiar periódicamente la caché para eliminar las entradas "muertas".
+Otra opción es usar finalizadores, que exploraremos a continuación.  
+
+
+## Ejemplo №2: Usando WeakRef para rastrear objetos del DOM
+
+Otro caso de uso de `WeakRef` es rastrear objetos del DOM. 
+
+Imaginemos un escenario en el que un código o biblioteca de terceros interactúa con elementos de nuestra página mientras existan en el DOM.
+Por ejemplo, podría ser una utilidad externa que monitorea y notifica el estado del sistema (comúnmente llamada "logger", un programa que envía mensajes informativos llamados "logs").
+
+Ejemplo interactivo:
+
+[codetabs height=420 src="weakref-dom"]
+
+Cuando se hace clic en el botón "Iniciar envío de mensajes", comienzan a aparecer mensajes (logs) en la llamada "ventana de visualización de logs" (un elemento con la clase `.window__body`).
+
+Sin embargo, tan pronto como este elemento es eliminado del DOM, el logger debería dejar de enviar mensajes.
+Para simular la eliminación de este elemento, simplemente haz clic en el botón "Cerrar" en la esquina superior derecha.
+
+Para evitar la necesidad de notificar al código externo cada vez que nuestro elemento DOM está disponible o no, podemos simplemente crear una referencia débil con `WeakRef`.
+
+Una vez que el elemento es eliminado del DOM, el logger lo detectará y dejará de enviar mensajes.
+
+Ahora veamos en detalle el código fuente (*pestaña `index.js`*):
+
+1. Obtener el elemento DOM del botón "Iniciar envío de mensajes".
+2. Obtener el elemento DOM del botón "Cerrar".
+3. Obtener el elemento DOM de la ventana de logs usando el constructor `new WeakRef()`. De esta manera, la variable `windowElementRef` mantiene una referencia débil al elemento del DOM.
+4. Agregar un event listener al botón "Iniciar envío de mensajes", que inicia el logger cuando se hace clic.
+5. Agregar un event listener al botón "Cerrar", que elimina la ventana de logs del DOM cuando se hace clic.
+6. Usar  `setInterval` para mostrar un nuevo mensaje cada segundo.
+7. Si el elemento DOM de la ventana de logs sigue disponible en memoria, crear y enviar un nuevo mensaje.
+8. Si el método `deref()` devuelve `undefined`, significa que el elemento DOM ha sido eliminado de la memoria. En este caso, el logger deja de mostrar mensajes y se limpia el temporizador.
+9. Mostrar un`alert`, cuando el elemento DOM de la ventana de logs haya sido eliminado de la memoria (es decir, después de hacer clic en el botón "Cerrar"). **Nota: La eliminación de la memoria puede no ocurrir de inmediato, ya que depende únicamente de los mecanismos internos del recolector de basura.**
+
+   No podemos controlar este proceso directamente desde el código. Sin embargo, aún es posible forzar la recolección de basura en el navegador.
+
+   En Google Chrome, por ejemplo, para hacer esto, abre las herramientas para desarrolladores (`key:Ctrl` + `key:Shift` + `key:J` en Windows/Linux o `key:Option` + `key:⌘` + `key:J` en macOS), ve a la pestaña "Performance" y haz clic en el ícono de la papelera – "Collect garbage":
+
+   ![](google-chrome-developer-tools.png)
+
+    <br>
+     Esta funcionalidad está disponible en la mayoría de los navegadores modernos. Después de realizar estos pasos, el  <code>alert</code> se activará inmediatamente.
+
+## FinalizationRegistry
+
+Es momento de hablar sobre los finalizadores. Aclaremos la terminología antes de continuar:  
+
+**Callback de limpieza (finalizador)** -- es una función que se ejecuta cuando un objeto registrado en `FinalizationRegistry` es eliminado de la memoria por el recolector de basura.
+
+Su propósito es permitir realizar operaciones adicionales relacionadas con el objeto después de que haya sido eliminado de la memoria.
+
+**Registro** (o `FinalizationRegistry`) -- es un objeto especial en JavaScript que gestiona el alta y la eliminación de objetos referent junto con sus callbacks de limpieza. 
+
+Este mecanismo permite registrar un objeto para rastrearlo y asociarle un callback de limpieza.
+Básicamente, es una estructura que almacena información sobre los objetos registrados y sus callbacks de limpieza, y luego los invoca automáticamente cuando los objetos son eliminados de la memoria.
+
+Para crear una instancia de `FinalizationRegistry`, se debe llamar a su constructor, el que recibe un solo argumento: el callback de limpieza (el finalizador).
+
+Sintaxis:
+
+```js
+function cleanupCallback(heldValue) { 
+  // código del callback de limpieza 
+}
+
+const registry = new FinalizationRegistry(cleanupCallback);
+```
+
+Donde:
+
+- `cleanupCallback` -- es la función que se ejecutará automáticamente cuando un objeto registrado sea eliminado de la memoria.
+- `heldValue` -- es el valor que se pasará como argumento al callback de limpieza. Si `heldValue`  es un objeto, el registro mantiene una referencia fuerte a él.
+- `registry` -- es la instancia de `FinalizationRegistry`.
+
+Métodos de `FinalizationRegistry`:
+
+- `register(target, heldValue [, unregisterToken])` -- registra un objeto en el registro.
+
+  `target` --  el objeto a registrar. Si `target` es recolectado por el recolector de basura, el callback de limpieza se ejecutará con `heldValue` como argumento.
+
+  Opcional `unregisterToken` -- un token de desregistro. Se puede usar para anular el registro de un objeto antes de que el recolector de basura lo elimine. Por convención, suele ser el mismo `target`.
+- `unregister(unregisterToken)` -- elimina un objeto del registro. Recibe un argumento: `unregisterToken` (el token usado al registrar el objeto).
+
+Veamos un ejemplo. Usemos el ya conocido objeto `user` y creemos una instancia de `FinalizationRegistry`:
+
+```js
+let user = { name: "John" };
+
+const registry = new FinalizationRegistry((heldValue) => {
+  console.log(`${heldValue} ha sido recolectado por el recolector de basura.`);
+});
+```
+
+Luego, registramos el objeto que requiere limpieza llamando al método `register`:
+
+```js
+registry.register(user, user.name);
+```
+
+El registro no mantiene una referencia fuerte al objeto, ya que eso impediría que el recolector de basura lo eliminara.
+
+Si el objeto es eliminado por el recolector de basura, el callback de limpieza puede ejecutarse en algún momento futuro con el `heldValue` pasado como argumento:
+
+```js
+// Cuando el objeto user sea eliminado, se imprimirá en la consola:
+"John ha sido recolectado por el recolector de basura."
+```
+
+Hay casos donde el callback tiene posibilidades de no ejecutarse.
+
+Por ejemplo:
+- Cuando el programa termina por completo su operación (por ejemplo, al cerrar una pestaña en el navegador).
+- Cuando la instancia de `FinalizationRegistry` mismo deja de estar accesible en el código.
+  Si el objeto que creó la instancia de `FinalizationRegistry` sale del ámbito o es eliminado, los callbacks de limpieza registrados en tal registro podrían no ser invocados.
+
+## Caché con FinalizationRegistry
+
+Volviendo a nuestro ejemplo de caché *débil*, podemos notar lo siguiente:
+- Aunque los valores envueltos en `WeakRef` hayan sido recolectados por el recolector de basura, sigue existiendo un problema de "fuga de memoria" debido a las claves restantes cuyos valores han sido eliminados.
+
+Esta es una versión mejorada de la caché usando `FinalizationRegistry`:
+
+```js
+function fetchImg() {
+  // función abstracta para descargar imágenes...
+}
+
+function weakRefCache(fetchImg) {
+  const imgCache = new Map();
+
+  *!*
+  const registry = new FinalizationRegistry((imgName) => { // (1)
+    const cachedImg = imgCache.get(imgName);
+    if (cachedImg && !cachedImg.deref()) imgCache.delete(imgName);
+  });
+  */!*
+
+  return (imgName) => {
+    const cachedImg = imgCache.get(imgName);
+    
+    if (cachedImg?.deref()) {
+      return cachedImg?.deref();
+    }
+
+    const newImg = fetchImg(imgName);
+    imgCache.set(imgName, new WeakRef(newImg));
+    *!*
+    registry.register(newImg, imgName); // (2)
+    */!*
+
+    return newImg;
+  };
+}
+
+const getCachedImg = weakRefCache(fetchImg);
+```
+
+1. Para gestionar la limpieza de las entradas "muertas" de la caché cuando los objetos `WeakRef`  son eliminados por el recolector de basura, creamos un registro de limpieza con `FinalizationRegistry`.
+
+   Es importante comprobar en el callback de limpieza si la entrada fue eliminada por el recolector y no ha sido reinsertada, para evitar borrar una entrada "viva".
+2. Una vez que se descarga una nueva imagen y se almacena en la caché, la registramos en el `FinalizationRegistry` para rastrear el objeto `WeakRef`.
+
+Esta implementación solo mantiene pares clave/valor realmente "vivos". 
+En este caso, cada objeto `WeakRef` se registra en `FinalizationRegistry`.
+Y después de que los objetos sean eliminados por el recolector de basura, el callback de limpieza eliminará todas las entradas `undefined`.
+
+Aquí la representación visual del código actualizado:
+
+![](weakref-finalizationregistry-05.svg)
+
+Un aspecto clave de esta implementación es que los finalizadores permiten la ejecución en paralelo entre el programa principal y los callbacks de limpieza.
+En el contexto de JavaScript, el "programa principal" es el código JavaScript que se ejecuta en nuestra aplicación o página web.  
+
+Por lo tanto, desde el momento en que un objeto es marcado para eliminación por el recolector de basura hasta que el callback de limpieza se ejecuta, puede haber un cierto lapso.
+Es importante entender que, durante este tiempo, el programa principal puede modificar el objeto o incluso restaurarlo en la memoria.  
+
+Por eso, en el callback de limpieza debemos verificar si la entrada ha sido agregada nuevamente a la caché para evitar eliminar valores "vivos".
+Del mismo modo, al buscar una clave en la caché, existe la posibilidad de que su valor haya sido eliminado por el recolector de basura, pero el callback de limpieza aún no se haya ejecutado.
+
+Estas situaciones requieren especial atención si trabajas con `FinalizationRegistry`.
+
+## Uso de WeakRef y FinalizationRegistry en la práctica
+
+Pasando de la teoría a la práctica, imaginemos un escenario real en el que un usuario sincroniza sus fotos en un dispositivo móvil con un servicio en la nube
+(como [iCloud](https://en.wikipedia.org/wiki/ICloud) o [Google Photos](https://en.wikipedia.org/wiki/Google_Photos)), y quiere verlas desde otros dispositivos.
+Además de la funcionalidad básica de visualización, estos servicios ofrecen características adicionales como:
+
+- Edición de fotos y efectos de video.
+- Creación de "recuerdos" y álbumes.
+- Montajes de video a partir de una serie de fotos.
+- ... y mucho más.
+
+Aquí, como ejemplo, usaremos una implementación bastante primitiva de un servicio similar.
+El objetivo principal es mostrar un posible escenario en el que `WeakRef` y `FinalizationRegistry` se utilicen juntos en una aplicación real.
+
+Así es como se ve:
+
+![](weakref-finalizationregistry-demo-01.png)
+
+<br>
+A la izquierda, hay una biblioteca de fotos en la nube (mostradas como miniaturas).
+Podemos seleccionar imágenes y crear un collage haciendo clic en el botón "Crear collage" en la derecha.
+Luego, el collage resultante se puede descargar como una imagen.
+</br><br>
+
+Para acelerar la carga de la página, lo lógico es descargar y mostrar las miniaturas en calidad *comprimida*,
+pero al crear el collage, descargar y usar las imágenes en *calidad completa*.
+
+Las miniaturas tienen un tamaño de 240x240 píxeles.
+Este tamaño se eligió intencionalmente para optimizar la velocidad de carga.
+En el modo de vista previa, tampoco necesitamos imágenes en tamaño completo.
+
+![](weakref-finalizationregistry-demo-02.png)
+
+<br>
+Supongamos que queremos crear un collage con 4 fotos. Las seleccionamos y hacemos clic en "Crear collage".
+Aquí, la ya conocida función <code>weakRefCache</code> verifica si la imagen requerida está en caché.
+Si no lo está, la descarga desde la nube y la almacena para futuros usos.
+Esto ocurre para cada imagen seleccionada:
+</br><br>
+
+![](weakref-finalizationregistry-demo-03.gif)
+
+</br>
+
+Al observar la consola podemos ver qué fotos fueron descargadas desde la nube, indicadas por <span style="background-color:#133159;color:white;font-weight:500">FETCHED_IMAGE</span>.
+Como es la primera vez que se crea el collage, la "caché débil" estaba vacía, así que todas las imágenes se descargaron de la nube.
+
+Pero al mismo tiempo el recolector de basura está limpiando la memoria.
+Esto significa que las imágenes almacenadas con referencias débiles pueden ser eliminadas.
+Cuando esto sucede, nuestro finalizador borra la clave correspondiente de la caché.
+<span style="background-color:#901e30;color:white;font-weight:500;">CLEANED_IMAGE</span> nos lo notifica:
+
+![](weakref-finalizationregistry-demo-04.jpg)
+
+<br>
+Después, nos damos cuenta de que no nos gusta el collage y decidimos cambiar una de las imágenes.
+Para esto, desmarcamos una, seleccionamos otra y hacemos clic en "Crear collage" de nuevo:
+</br><br>
+
+![](weakref-finalizationregistry-demo-05.gif)
+
+<br>
+Pero esta vez, no todas las imágenes se descargaron de la red, algunas se obtuvieron de la caché débil, como indica el mensaje <span style="background-color:#385950;color:white;font-weight:500;">CACHED_IMAGE</span>.
+Esto significa que el recolector de basura aún no eliminó algunas imágenes,
+lo que reduce el número de descargas y acelera el proceso de creación del collage.
+</br><br>
+
+![](weakref-finalizationregistry-demo-06.jpg)
+
+<br>
+Juguemos un poco más. Volvamos a cambiar otra imagen y creemos un nuevo collage:
+</br><br>
+
+![](weakref-finalizationregistry-demo-07.gif)
+
+<br>
+Esta vez, el resultado es aún mejor. De las 4 imágenes seleccionadas, 3 fueron recuperadas de la caché débil y solo una tuvo que descargarse.
+La reducción en el uso de la red fue del 75%. Nada mal.
+</br><br>
+
+![](weakref-finalizationregistry-demo-08.jpg)
+
+</br>
+
+Es importante recordar que este comportamiento no está garantizado y depende de la implementación específica del recolector de basura.
+
+Dicho esto, surge una pregunta lógica: ¿por qué no usar una caché normal, que podamos gestionar manualmente en lugar de depender del recolector de basura?
+En la mayoría de los casos, no hay necesidad de usar `WeakRef` y `FinalizationRegistry`.
+
+Aquí simplemente demostramos una alternativa con un enfoque diferente y características interesantes del lenguaje.
+Sin embargo, este ejemplo no es fiable si necesitamos resultados constantes y predecibles.
+
+Puedes [abrir este ejemplo en el sandbox.](sandbox:weakref-finalizationregistry).
+
+## Resumen
+
+`WeakRef` -- está diseñado para crear referencias débiles a objetos, lo que permite que el recolector de basura los elimine si no hay referencias fuertes a ellos.
+Esto habilita al motor de JavaScript optimizar el uso de memoria y recursos del sistema.
+
+`FinalizationRegistry` -- permite registrar callbacks que se ejecutan cuando un objeto sin referencias fuertes es eliminado.
+Esto permite liberar manualmente recursos asociados al objeto o realizar tareas de limpieza adicionales antes de que el objeto desaparezca de la memoria.
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/google-chrome-developer-tools.png b/1-js/99-js-misc/07-weakref-finalizationregistry/google-chrome-developer-tools.png
new file mode 100644
index 000000000..021637342
Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/google-chrome-developer-tools.png differ
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.css b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.css
new file mode 100644
index 000000000..f6df812d0
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.css
@@ -0,0 +1,49 @@
+.app {
+    display: flex;
+    flex-direction: column;
+    gap: 16px;
+}
+
+.start-messages {
+    width: fit-content;
+}
+
+.window {
+    width: 100%;
+    border: 2px solid #464154;
+    overflow: hidden;
+}
+
+.window__header {
+    position: sticky;
+    padding: 8px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    background-color: #736e7e;
+}
+
+.window__title {
+    margin: 0;
+    font-size: 24px;
+    font-weight: 700;
+    color: white;
+    letter-spacing: 1px;
+}
+
+.window__button {
+    padding: 4px;
+    background: #4f495c;
+    outline: none;
+    border: 2px solid #464154;
+    color: white;
+    font-size: 16px;
+    cursor: pointer;
+}
+
+.window__body {
+    height: 250px;
+    padding: 16px;
+    overflow: scroll;
+    background-color: #736e7e33;
+}
\ No newline at end of file
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.html b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.html
new file mode 100644
index 000000000..7f93af4c7
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.html
@@ -0,0 +1,28 @@
+<!DOCTYPE HTML>
+<html lang="en">
+
+<head>
+  <meta charset="utf-8">
+  <link rel="stylesheet" href="index.css">
+  <title>WeakRef DOM Logger</title>
+</head>
+
+<body>
+
+<div class="app">
+  <button class="start-messages">Start sending messages</button>
+  <div class="window">
+    <div class="window__header">
+      <p class="window__title">Messages:</p>
+      <button class="window__button">Close</button>
+    </div>
+    <div class="window__body">
+      No messages.
+    </div>
+  </div>
+</div>
+
+
+<script type="module" src="index.js"></script>
+</body>
+</html>
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.js b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.js
new file mode 100644
index 000000000..ea55b4478
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.js
@@ -0,0 +1,24 @@
+const startMessagesBtn = document.querySelector('.start-messages'); // (1)
+const closeWindowBtn = document.querySelector('.window__button'); // (2)
+const windowElementRef = new WeakRef(document.querySelector(".window__body")); // (3)
+
+startMessagesBtn.addEventListener('click', () => { // (4)
+    startMessages(windowElementRef);
+    startMessagesBtn.disabled = true;
+});
+
+closeWindowBtn.addEventListener('click', () =>  document.querySelector(".window__body").remove()); // (5)
+
+
+const startMessages = (element) => {
+    const timerId = setInterval(() => { // (6)
+        if (element.deref()) { // (7)
+            const payload = document.createElement("p");
+            payload.textContent = `Message: System status OK: ${new Date().toLocaleTimeString()}`;
+            element.deref().append(payload);
+        } else { // (8)
+            alert("The element has been deleted."); // (9)
+            clearInterval(timerId);
+        }
+    }, 1000);
+};
\ No newline at end of file
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-01.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-01.svg
new file mode 100644
index 000000000..2a507dbcd
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-01.svg
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg viewBox="-38.324 -109.673 191.121 281.642" width="191.121px" height="281.642px" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
+  <defs>
+    <style bx:fonts="Open Sans">@import url(https://fonts.googleapis.com/css2?family=Open+Sans%3Aital%2Cwght%400%2C300%3B0%2C400%3B0%2C500%3B0%2C600%3B0%2C700%3B0%2C800%3B1%2C300%3B1%2C400%3B1%2C500%3B1%2C600%3B1%2C700%3B1%2C800&amp;display=swap);</style>
+  </defs>
+  <g id="garbage-collection" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1" transform="matrix(1.6492669582366946, 0, 0, 1.6492669582366946, -81.42222595214844, 62.8305015563965)" style="">
+    <g id="memory-user-john-admin.svg" transform="matrix(1, 0, 0, 1, -1.759865, 4.803441)">
+      <text id="user" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 14px; font-weight: 600; white-space: pre;" transform="matrix(0.735667, 0, 0, 0.753868, 7.56361, 10.722544)" x="31.917" y="-40.191">user</text>
+      <path id="Rectangle-4" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 39.02 4.206 L 125.8 4.206 L 125.8 48.227 L 39.02 48.227 L 39.02 4.206 Z" style=""/>
+      <text id="name:-&quot;John&quot;" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 9px; font-weight: 500; white-space: pre;" x="54.086" y="34.58">name: "John"</text>
+      <text id="Object" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 10.5px; font-weight: 500; white-space: pre;" x="64.679" y="23.487">Object</text>
+      <path id="Rectangle-1" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 36.398 -102.608 L 129.398 -102.608 L 129.398 -76.608 L 36.398 -76.608 L 36.398 -102.608 Z"/>
+      <text id="&lt;global&gt;" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 10.6px; font-weight: 500; white-space: pre;" x="59.233" y="-86.001"> &lt;global&gt;</text>
+      <path d="M 105.999 1.57 L 113.013 13.895 L 98.985 13.895 L 105.999 1.57 Z" style="fill-rule: nonzero; fill: rgb(172, 67, 67);" transform="matrix(1, 0, 0, -1, 0, 0)" bx:shape="triangle 98.985 1.57 14.028 12.325 0.5 0 1@df7d9fa9"/>
+      <g>
+        <rect x="105.024" y="-69.436" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-59.02" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-48.877" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+      </g>
+      <g transform="matrix(1, 0, 0, 1.024052, -0.03572, 31.45084)" style="">
+        <rect x="105.024" y="-69.051" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-59.02" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-48.877" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+      </g>
+      <g transform="matrix(1, 0, 0, 1, -9.930843, 12.564639)">
+        <path d="M 66.874 14.118 L 73.888 26.443 L 59.86 26.443 L 66.874 14.118 Z" style="fill-rule: nonzero; fill: rgb(192, 99, 52);" transform="matrix(1, 0, 0, -1, 0, 0)" bx:shape="triangle 59.86 14.118 14.028 12.325 0.5 0 1@9d4d6098"/>
+        <rect x="65.833" y="-81.984" width="2.056" height="55.884" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(192, 99, 52);"/>
+      </g>
+      <text id="text-1" style="fill: rgb(172, 67, 67); font-family: 'Open Sans'; font-size: 14px; font-weight: 600; white-space: pre;" transform="matrix(0.735667, 0, 0, 0.753868, 87.03299, 10.790039)" x="31.917" y="-40.191">admin</text>
+    </g>
+  </g>
+</svg>
\ No newline at end of file
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-02.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-02.svg
new file mode 100644
index 000000000..6cc199a12
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-02.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg viewBox="-56.888 -212.944 192.167 294.011" width="178.044px" height="272.403px" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
+  <defs>
+    <style bx:fonts="Open Sans">@import url(https://fonts.googleapis.com/css2?family=Open+Sans%3Aital%2Cwght%400%2C300%3B0%2C400%3B0%2C500%3B0%2C600%3B0%2C700%3B0%2C800%3B1%2C300%3B1%2C400%3B1%2C500%3B1%2C600%3B1%2C700%3B1%2C800&amp;display=swap);</style>
+  </defs>
+  <g id="garbage-collection" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1" transform="matrix(1.708757996559143, 0, 0, 1.708757996559143, -109.71231842041016, -35.19435119628906)" style="">
+    <g id="memory-user-john-admin.svg" transform="matrix(1, 0, 0, 1, -1.759865, 4.803441)">
+      <path id="Rectangle-4" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 39.02 4.206 L 125.8 4.206 L 125.8 48.227 L 39.02 48.227 L 39.02 4.206 Z" style=""/>
+      <path id="Rectangle-1" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 36.398 -102.608 L 129.398 -102.608 L 129.398 -76.608 L 36.398 -76.608 L 36.398 -102.608 Z"/>
+      <text id="&lt;global&gt;" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 10.8px; font-weight: 500; white-space: pre;" x="57.977" y="-85.926"> &lt;global&gt;</text>
+      <path d="M 105.999 1.57 L 113.013 13.895 L 98.985 13.895 L 105.999 1.57 Z" style="fill-rule: nonzero; fill: rgb(172, 67, 67);" transform="matrix(1, 0, 0, -1, 0, 0)" bx:shape="triangle 98.985 1.57 14.028 12.325 0.5 0 1@df7d9fa9"/>
+      <g style="" transform="matrix(0.7989, 0, 0, 0.7989, 13.076554, 6.083323)">
+        <text id="name:-&quot;John&quot;" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 12px; font-weight: 500; white-space: pre;" x="48.212" y="37.89">name: "John"</text>
+        <text id="Object" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 14px; font-weight: 500; white-space: pre;" x="61.598" y="23.794">Object</text>
+      </g>
+      <g>
+        <rect x="105.024" y="-69.436" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-59.02" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-48.877" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+      </g>
+      <g transform="matrix(1, 0, 0, 1.024052, -0.03572, 31.45084)" style="">
+        <rect x="105.024" y="-69.051" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-59.02" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-48.877" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+      </g>
+      <text id="text-1" style="fill: rgb(172, 67, 67); font-family: 'Open Sans'; font-size: 14px; font-weight: 600; white-space: pre;" transform="matrix(0.735667, 0, 0, 0.753868, 86.426659, 10.790039)" x="31.917" y="-40.191">admin</text>
+    </g>
+  </g>
+  <g transform="matrix(0.529145, 0, 0, 0.529145, -21.841589, -83.135681)" style="">
+    <path d="M80.179,13.758c-18.342-18.342-48.08-18.342-66.422,0c-18.342,18.341-18.342,48.08,0,66.421 c18.342,18.342,48.08,18.342,66.422,0C98.521,61.837,98.521,32.099,80.179,13.758z M44.144,83.117 c-4.057,0-7.001-3.071-7.001-7.305c0-4.291,2.987-7.404,7.102-7.404c4.123,0,7.001,3.044,7.001,7.404 C51.246,80.113,48.326,83.117,44.144,83.117z M54.73,44.921c-4.15,4.905-5.796,9.117-5.503,14.088l0.097,2.495 c0.011,0.062,0.017,0.125,0.017,0.188c0,0.58-0.47,1.051-1.05,1.051c-0.004-0.001-0.008-0.001-0.012,0h-7.867 c-0.549,0-1.005-0.423-1.047-0.97l-0.202-2.623c-0.676-6.082,1.508-12.218,6.494-18.202c4.319-5.087,6.816-8.865,6.816-13.145 c0-4.829-3.036-7.536-8.548-7.624c-3.403,0-7.242,1.171-9.534,2.913c-0.264,0.201-0.607,0.264-0.925,0.173 s-0.575-0.327-0.693-0.636l-2.42-6.354c-0.169-0.442-0.02-0.943,0.364-1.224c3.538-2.573,9.441-4.235,15.041-4.235 c12.36,0,17.894,7.975,17.894,15.877C63.652,33.765,59.785,38.919,54.73,44.921z" style="fill: rgb(172, 67, 67);"/>
+  </g>
+  <rect x="-52.271" y="-25.92" width="160.339" height="87.431" style="fill: rgba(216, 216, 216, 0); stroke: rgb(172, 67, 67); stroke-width: 3px;"/>
+</svg>
\ No newline at end of file
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-03.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-03.svg
new file mode 100644
index 000000000..949a14f9f
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-03.svg
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg viewBox="-46.534 -212.944 529.701 256.516" width="540.055px" height="256.516px" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
+  <defs>
+    <style bx:fonts="Open Sans">@import url(https://fonts.googleapis.com/css2?family=Open+Sans%3Aital%2Cwght%400%2C300%3B0%2C400%3B0%2C500%3B0%2C600%3B0%2C700%3B0%2C800%3B1%2C300%3B1%2C400%3B1%2C500%3B1%2C600%3B1%2C700%3B1%2C800&amp;display=swap);</style>
+  </defs>
+  <g id="memory-user-john-admin.svg" transform="matrix(1.7087579965591428, 0, 0, 1.7087579965591428, -443.0394287109375, -47.16891479492199)" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1">
+    <path id="path-1" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 234.068 -87.403 L 333.494 -87.403 L 333.494 -57.762 L 234.068 -57.762 L 234.068 -87.403 Z" style=""/>
+    <path id="path-2" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 336.651 -87.403 L 492.549 -87.403 L 492.549 -57.762 L 336.651 -57.762 L 336.651 -87.403 Z" style=""/>
+    <path id="path-3" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 234.068 -53.711 L 333.494 -53.711 L 333.494 -24.07 L 234.068 -24.07 L 234.068 -53.711 Z" style=""/>
+    <path id="path-4" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 336.651 -53.711 L 492.783 -53.711 L 492.783 -24.07 L 336.651 -24.07 L 336.651 -53.711 Z" style=""/>
+    <path id="path-5" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 234.189 -20.462 L 333.615 -20.462 L 333.615 9.179 L 234.189 9.179 L 234.189 -20.462 Z" style=""/>
+    <path id="path-6" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 336.791 -20.462 L 493.057 -20.462 L 493.057 9.179 L 336.791 9.179 L 336.791 -20.462 Z" style=""/>
+    <path id="path-7" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 234.068 13.088 L 333.494 13.088 L 333.494 43.59 L 234.068 43.59 L 234.068 13.088 Z" style=""/>
+    <path id="path-8" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 336.651 13.088 L 493.054 13.088 L 493.054 43.59 L 336.651 43.59 L 336.651 13.088 Z" style=""/>
+    <text id="&lt;global&gt;" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 11.5772px; font-weight: 600; line-height: 19.9484px; white-space: pre;" transform="matrix(1.374145, 0, 0, 1.314286, -102.41082, 25.040792)" x="263.861" y="-70.535">key</text>
+    <text id="text-2" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 11.5772px; font-weight: 600; line-height: 19.9484px; white-space: pre;" transform="matrix(1.374145, 0, 0, 1.314286, 13.577469, 25.203112)" x="263.861" y="-70.535">value</text>
+    <text id="text-3" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 14px; white-space: pre;" transform="matrix(1.071654, 0, 0, 1.142641, -43.57296, 46.390514)" x="263.861" y="-70.535">image-01.jpg</text>
+    <text id="text-4" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 14px; white-space: pre;" transform="matrix(1.054877, 0, 0, 1.142641, -39.02475, 80.086914)" x="263.861" y="-70.535">image-02.jpg</text>
+    <text id="text-5" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 14px; white-space: pre;" transform="matrix(1.054877, 0, 0, 1.142641, -39.468063, 113.637062)" x="263.861" y="-70.535">image-03.jpg</text>
+    <g transform="matrix(0.000041, -1, 1.521843, 0.000133, 289.017426, 2.750529)" style="transform-origin: 105.999px -35.503px;">
+      <path d="M 105.537 7.964 L 110.918 13.895 L 100.155 13.895 L 105.537 7.964 Z" style="fill-rule: nonzero; fill: rgb(172, 67, 67);" transform="matrix(1, 0, 0, -1, 0, 0)" bx:shape="triangle 100.155 7.964 10.763 5.931 0.5 0 1@87a4267a"/>
+      <g>
+        <rect x="105.024" y="-69.436" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-59.02" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-48.877" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+      </g>
+      <g transform="matrix(1, 0, 0, 1.024052, -0.03572, 31.45084)" style="">
+        <rect x="105.024" y="-69.051" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-59.02" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-48.877" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+      </g>
+    </g>
+    <text id="text-6" style="fill: rgb(172, 67, 67); font-family: 'Open Sans'; font-size: 9.73113px; font-style: italic; white-space: pre;" transform="matrix(1.038937, 0, 0, 1.142641, 69.710487, 42.749538)" x="263.861" y="-70.535">WeakRef object</text>
+    <g transform="matrix(0.441364, 0, 0, 0.412845, 420.761139, -59.372555)" style="">
+      <g>
+        <path d=" M 58.15 23.65 L 58.15 20 54.25 20 Q 50.95 20 49.35 22.2 47.75 24.4 47.75 27.7 L 47.05 41.45 Q 46.8 43.25 46.1 44.6 45.45 46.05 44.35 47.05 43.9 47.55 43.2 47.75 42.8 47.95 41.85 48.15 L 41.85 51.6 Q 42.95 51.8 43.2 51.9 43.9 52.1 44.35 52.45 45.45 53.25 46.05 54.55 47.65 58.15 47.65 61.65 L 47.65 72.1 Q 47.65 75.7 49.45 77.85 51.25 80 54.1 80 L 58.15 80 58.15 76.25 55.25 76.25 Q 54.1 76.25 53.35 75.65 52.55 74.95 52.2 74 L 51.65 71.75 51.5 69.45 51.35 59.8 Q 51.35 57.55 50.8 55.8 50.15 53.65 49.65 52.8 48.8 51.5 47.9 50.8 47.05 50.1 46.1 49.75 47 49.3 47.8 48.7 48.95 47.85 49.6 46.75 50.1 45.8 50.75 43.7 51.35 41.85 51.35 39.45 L 51.55 28.05 52 25.9 Q 52.35 24.85 53.15 24.2 53.9 23.65 55.25 23.65 L 58.15 23.65 Z" style="fill: rgb(175, 110, 36);"/>
+      </g>
+    </g>
+    <g transform="matrix(-0.441364, 0, 0, -0.412845, 414.750092, -88.816727)" style="transform-origin: 50px 50px;">
+      <g>
+        <path d="M 14.392 23.65 L 14.392 20 L 10.492 20 C 8.292 20 6.659 20.733 5.592 22.2 C 4.525 23.667 3.992 25.5 3.992 27.7 L 3.292 41.45 C 3.125 42.65 2.809 43.7 2.342 44.6 C 1.909 45.567 1.325 46.383 0.592 47.05 C 0.292 47.383 -0.091 47.617 -0.558 47.75 C -0.825 47.883 -1.275 48.017 -1.908 48.15 L -1.908 51.6 C -1.175 51.733 -0.725 51.833 -0.558 51.9 C -0.091 52.033 0.292 52.217 0.592 52.45 C 1.325 52.983 1.892 53.683 2.292 54.55 C 3.359 56.95 3.892 59.317 3.892 61.65 L 3.892 72.1 C 3.892 74.5 4.492 76.417 5.692 77.85 C 6.892 79.283 8.442 80 10.342 80 L 14.392 80 L 14.392 76.25 L 11.492 76.25 C 10.725 76.25 10.092 76.05 9.592 75.65 C 9.059 75.183 8.675 74.633 8.442 74 L 7.892 71.75 L 7.742 69.45 L 7.592 59.8 C 7.592 58.3 7.409 56.967 7.042 55.8 C 6.609 54.367 6.225 53.367 5.892 52.8 C 5.325 51.933 4.742 51.267 4.142 50.8 C 3.575 50.333 2.975 49.983 2.342 49.75 C 2.942 49.45 3.509 49.1 4.042 48.7 C 4.809 48.133 5.409 47.483 5.842 46.75 C 6.175 46.117 6.559 45.1 6.992 43.7 C 7.392 42.467 7.592 41.05 7.592 39.45 L 7.792 28.05 L 8.242 25.9 C 8.475 25.2 8.859 24.633 9.392 24.2 C 9.892 23.833 10.592 23.65 11.492 23.65 L 14.392 23.65 Z" style="fill: rgb(175, 110, 36);"/>
+        <path d="M 255.632 27.46 L 268.667 47.91 L 242.597 47.91 L 255.632 27.46 Z" style="fill-rule: nonzero; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, 1, 0.000093, 86.522967, -302.258205)" bx:shape="triangle 242.597 27.46 26.07 20.45 0.5 0 1@97f9cc39"/>
+        <rect x="254.391" y="-239.419" width="4.82" height="17.271" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, 86.522728, -302.258331)"/>
+        <rect x="254.367" y="-203.504" width="4.82" height="17.271" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, 86.522728, -302.258331)"/>
+        <rect x="254.367" y="-168.53" width="4.82" height="17.271" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, 86.522728, -302.258331)"/>
+        <rect x="254.391" y="-243.818" width="4.82" height="17.687" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, -21.921179, -302.35498)"/>
+        <rect x="254.367" y="-208.398" width="4.82" height="17.687" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, -21.921179, -302.35498)"/>
+        <rect x="254.367" y="-172.584" width="4.82" height="17.687" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, -21.921179, -302.35498)"/>
+        <text id="text-7" style="fill: rgb(172, 67, 67); font-family: 'Open Sans'; font-size: 9.73113px; font-style: italic; white-space: pre;" transform="matrix(-2.353923, 0, 0, -2.767724, 945.975708, -228.376572)" x="263.861" y="-70.535">WeakRef object</text>
+        <path d="M 108.749 -57.365 L 108.749 -61.015 L 104.849 -61.015 C 102.649 -61.015 101.015 -60.281 99.949 -58.815 C 98.882 -57.348 98.349 -55.515 98.349 -53.315 L 97.649 -39.565 C 97.482 -38.365 97.165 -37.315 96.699 -36.415 C 96.265 -35.448 95.682 -34.631 94.949 -33.965 C 94.649 -33.631 94.265 -33.398 93.799 -33.265 C 93.532 -33.131 93.082 -32.998 92.449 -32.865 L 92.449 -29.415 C 93.182 -29.281 93.632 -29.181 93.799 -29.115 C 94.265 -28.981 94.649 -28.798 94.949 -28.565 C 95.682 -28.031 96.249 -27.331 96.649 -26.465 C 97.715 -24.065 98.249 -21.698 98.249 -19.365 L 98.249 -8.915 C 98.249 -6.515 98.849 -4.598 100.049 -3.165 C 101.249 -1.731 102.799 -1.015 104.699 -1.015 L 108.749 -1.015 L 108.749 -4.765 L 105.849 -4.765 C 105.082 -4.765 104.449 -4.965 103.949 -5.365 C 103.415 -5.831 103.032 -6.381 102.799 -7.015 L 102.249 -9.265 L 102.099 -11.565 L 101.949 -21.215 C 101.949 -22.715 101.765 -24.048 101.399 -25.215 C 100.965 -26.648 100.582 -27.648 100.249 -28.215 C 99.682 -29.081 99.099 -29.748 98.499 -30.215 C 97.932 -30.681 97.332 -31.031 96.699 -31.265 C 97.299 -31.565 97.865 -31.915 98.399 -32.315 C 99.165 -32.881 99.765 -33.531 100.199 -34.265 C 100.532 -34.898 100.915 -35.915 101.349 -37.315 C 101.749 -38.548 101.949 -39.965 101.949 -41.565 L 102.149 -52.965 L 102.599 -55.115 C 102.832 -55.815 103.215 -56.381 103.749 -56.815 C 104.249 -57.181 104.949 -57.365 105.849 -57.365 L 108.749 -57.365 Z" style="fill: rgb(175, 110, 36); transform-box: fill-box; transform-origin: 50% 50%;" transform="matrix(-1, 0, 0, -1, -0.000004, -0.000028)"/>
+        <path d="M 15.325 -57.155 L 15.325 -60.805 L 11.425 -60.805 C 9.225 -60.805 7.591 -60.072 6.525 -58.605 C 5.458 -57.139 4.925 -55.305 4.925 -53.105 L 4.225 -39.355 C 4.058 -38.155 3.741 -37.105 3.275 -36.205 C 2.841 -35.239 2.258 -34.422 1.525 -33.755 C 1.225 -33.422 0.841 -33.189 0.375 -33.055 C 0.108 -32.922 -0.342 -32.789 -0.975 -32.655 L -0.975 -29.205 C -0.242 -29.072 0.208 -28.972 0.375 -28.905 C 0.841 -28.772 1.225 -28.589 1.525 -28.355 C 2.258 -27.822 2.825 -27.122 3.225 -26.255 C 4.291 -23.855 4.825 -21.489 4.825 -19.155 L 4.825 -8.705 C 4.825 -6.305 5.425 -4.389 6.625 -2.955 C 7.825 -1.522 9.375 -0.805 11.275 -0.805 L 15.325 -0.805 L 15.325 -4.555 L 12.425 -4.555 C 11.658 -4.555 11.025 -4.755 10.525 -5.155 C 9.991 -5.622 9.608 -6.172 9.375 -6.805 L 8.825 -9.055 L 8.675 -11.355 L 8.525 -21.005 C 8.525 -22.505 8.341 -23.839 7.975 -25.005 C 7.541 -26.439 7.158 -27.439 6.825 -28.005 C 6.258 -28.872 5.675 -29.539 5.075 -30.005 C 4.508 -30.472 3.908 -30.822 3.275 -31.055 C 3.875 -31.355 4.441 -31.705 4.975 -32.105 C 5.741 -32.672 6.341 -33.322 6.775 -34.055 C 7.108 -34.689 7.491 -35.705 7.925 -37.105 C 8.325 -38.339 8.525 -39.755 8.525 -41.355 L 8.725 -52.755 L 9.175 -54.905 C 9.408 -55.605 9.791 -56.172 10.325 -56.605 C 10.825 -56.972 11.525 -57.155 12.425 -57.155 L 15.325 -57.155 Z" style="fill: rgb(175, 110, 36);"/>
+      </g>
+    </g>
+  </g>
+  <g transform="matrix(0.3355039954185486, 0, 0, 0.3355039954185486, 67.31304168701172, -387.90008544921875)" style="">
+    <g transform="matrix(0.178489, 0, 0, 0.175502, 747.077209, 776.317017)" style="">
+      <path d="M 267.184 437.8 C 267.184 466.3 290.384 489.4 318.784 489.4 L 704.984 489.4 C 733.484 489.4 756.584 466.2 756.584 437.8 L 756.584 51.6 C 756.584 23.1 733.384 0 704.984 0 L 318.784 0 C 290.284 0 267.184 23.2 267.184 51.6 C 267.184 51.6 267.184 437.8 267.184 437.8 Z M 704.984 464.9 L 318.784 464.9 C 303.884 464.9 291.684 452.7 291.684 437.8 L 291.684 373.3 L 384.484 280.5 L 463.784 359.8 C 468.584 364.6 476.284 364.6 481.084 359.8 L 624.284 216.6 L 732.084 324.4 L 732.084 437.8 C 732.084 452.7 719.884 464.9 704.984 464.9 Z M 318.784 24.5 L 704.984 24.5 C 719.884 24.5 732.084 36.7 732.084 51.6 L 732.084 289.7 L 632.884 190.6 C 628.084 185.8 620.384 185.8 615.584 190.6 L 472.384 333.8 L 393.084 254.5 C 388.284 249.7 380.584 249.7 375.784 254.5 L 291.684 338.6 L 291.684 51.6 C 291.684 36.7 303.884 24.5 318.784 24.5 Z" style="fill: rgb(175, 110, 36);"/>
+      <path d="M 418.884 196.1 C 453.284 196.1 481.184 168.1 481.184 133.8 C 481.184 99.5 453.184 71.5 418.884 71.5 C 384.584 71.5 356.584 99.5 356.584 133.8 C 356.584 168.1 384.484 196.1 418.884 196.1 Z M 418.884 96 C 439.784 96 456.684 113 456.684 133.8 C 456.684 154.6 439.684 171.6 418.884 171.6 C 398.084 171.6 381.084 154.6 381.084 133.8 C 381.084 113 397.984 96 418.884 96 Z" style="fill: rgb(175, 110, 36);"/>
+    </g>
+  </g>
+  <path d="M -161.945 -20.71 L -152.75 -5.287 L -171.141 -5.287 L -161.945 -20.71 Z" style="fill-rule: nonzero; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -0.9999999999999999, -0.9999999999999999, -0.00008700000762473792, 281.6644897460937, -149.34440612792974)" bx:shape="triangle -171.141 -20.71 18.391 15.423 0.5 0 1@d86e5ee8"/>
+  <rect x="179.461" y="-180.566" width="3.4" height="13.026" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -0.9999999999999999, 0.9999999999999999, 0.00008700000762473792, 323.0706176757812, 192.94052124023426)"/>
+  <rect x="179.444" y="-153.479" width="3.4" height="13.026" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -0.9999999999999999, 0.9999999999999999, 0.00008700000762473792, 323.0706176757812, 192.94052124023426)"/>
+  <rect x="179.444" y="-127.103" width="3.4" height="13.026" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -0.9999999999999999, 0.9999999999999999, 0.00008700000762473792, 323.0706176757812, 192.94052124023426)"/>
+  <rect x="179.461" y="-183.883" width="3.4" height="13.339" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -0.9999999999999999, 0.9999999999999999, 0.00008700000762473792, 404.85729980468744, 193.00871276855457)"/>
+  <rect x="179.444" y="-157.171" width="3.4" height="13.339" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -0.9999999999999999, 0.9999999999999999, 0.00008700000762473792, 404.85729980468744, 193.00871276855457)"/>
+  <rect x="179.444" y="-130.16" width="3.4" height="13.339" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -0.9999999999999999, 0.9999999999999999, 0.00008700000762473792, 404.85729980468744, 193.00871276855457)"/>
+  <text id="text-8" style="fill: rgb(172, 67, 67); font-family: 'Open Sans'; font-size: 9.73113px; font-style: italic; white-space: pre;" transform="matrix(1.7752919197082517, 0, 0, 1.9524970054626463, -325.1152648925781, 140.82048034667957)" x="263.861" y="-70.535">WeakRef object</text>
+  <path d="M 318.601 -16.998 L 318.601 -19.573 L 315.66 -19.573 C 314.001 -19.573 312.769 -19.055 311.964 -18.021 C 311.16 -16.986 310.758 -15.693 310.758 -14.141 L 310.23 -4.441 C 310.104 -3.594 309.865 -2.853 309.513 -2.218 C 309.186 -1.536 308.746 -0.96 308.193 -0.49 C 307.967 -0.255 307.678 -0.09 307.326 0.004 C 307.125 0.098 306.786 0.192 306.308 0.286 L 306.308 2.72 C 306.861 2.814 307.2 2.884 307.326 2.931 C 307.678 3.025 307.967 3.155 308.193 3.319 C 308.746 3.696 309.174 4.189 309.475 4.801 C 310.28 6.494 310.682 8.163 310.682 9.81 L 310.682 17.181 C 310.682 18.875 311.135 20.227 312.04 21.238 C 312.945 22.249 314.114 22.755 315.547 22.755 L 318.601 22.755 L 318.601 20.109 L 316.414 20.109 C 315.836 20.109 315.358 19.968 314.981 19.686 C 314.579 19.357 314.29 18.969 314.114 18.522 L 313.699 16.935 L 313.586 15.312 L 313.473 8.504 C 313.473 7.446 313.334 6.506 313.058 5.683 C 312.731 4.671 312.442 3.966 312.191 3.566 C 311.763 2.955 311.323 2.485 310.871 2.155 C 310.443 1.826 309.991 1.579 309.513 1.415 C 309.966 1.203 310.393 0.956 310.795 0.674 C 311.373 0.274 311.826 -0.184 312.153 -0.702 C 312.404 -1.148 312.693 -1.866 313.02 -2.853 C 313.322 -3.723 313.473 -4.723 313.473 -5.852 L 313.623 -13.894 L 313.963 -15.41 C 314.139 -15.904 314.428 -16.304 314.83 -16.61 C 315.207 -16.868 315.735 -16.998 316.414 -16.998 L 318.601 -16.998 Z" style="fill: rgb(175, 110, 36);" transform="matrix(0.9999999999999999, 0, 0, 0.9999999999999999, 0, -1.1368683772161603e-13)"/>
+  <path d="M 389.058 -17.145 L 389.058 -19.72 L 386.117 -19.72 C 384.458 -19.72 383.226 -19.203 382.421 -18.168 C 381.617 -17.134 381.215 -15.84 381.215 -14.288 L 380.687 -4.588 C 380.561 -3.742 380.322 -3.001 379.97 -2.366 C 379.644 -1.684 379.204 -1.108 378.651 -0.638 C 378.424 -0.403 378.135 -0.238 377.783 -0.144 C 377.582 -0.05 377.243 0.044 376.765 0.138 L 376.765 2.572 C 377.318 2.666 377.658 2.737 377.783 2.784 C 378.135 2.878 378.424 3.007 378.651 3.172 C 379.204 3.548 379.631 4.042 379.933 4.653 C 380.737 6.346 381.139 8.016 381.139 9.662 L 381.139 17.034 C 381.139 18.727 381.592 20.079 382.497 21.09 C 383.402 22.101 384.571 22.607 386.004 22.607 L 389.058 22.607 L 389.058 19.961 L 386.871 19.961 C 386.293 19.961 385.815 19.82 385.438 19.538 C 385.036 19.209 384.747 18.821 384.571 18.374 L 384.156 16.787 L 384.043 15.164 L 383.93 8.357 C 383.93 7.299 383.792 6.358 383.515 5.535 C 383.188 4.524 382.899 3.818 382.648 3.419 C 382.22 2.807 381.78 2.337 381.328 2.008 C 380.901 1.679 380.448 1.432 379.97 1.267 C 380.423 1.055 380.85 0.808 381.253 0.526 C 381.831 0.127 382.283 -0.332 382.61 -0.849 C 382.861 -1.296 383.151 -2.013 383.477 -3.001 C 383.779 -3.871 383.93 -4.87 383.93 -5.999 L 384.081 -14.041 L 384.42 -15.558 C 384.596 -16.052 384.885 -16.452 385.287 -16.757 C 385.664 -17.016 386.192 -17.145 386.871 -17.145 L 389.058 -17.145 Z" style="fill: rgb(175, 110, 36); transform-origin: 382.912px 1.4435px;" transform="matrix(-1, 0, 0, -1, 0, -0.000015020371)"/>
+  <path d="M 333.236 -45.236 C 333.236 -43.558 334.625 -42.198 336.326 -42.198 L 359.453 -42.198 C 361.16 -42.198 362.543 -43.564 362.543 -45.236 L 362.543 -67.977 C 362.543 -69.655 361.154 -71.015 359.453 -71.015 L 336.326 -71.015 C 334.619 -71.015 333.236 -69.649 333.236 -67.977 C 333.236 -67.977 333.236 -45.236 333.236 -45.236 Z M 359.453 -43.641 L 336.326 -43.641 C 335.434 -43.641 334.703 -44.359 334.703 -45.236 L 334.703 -49.034 L 340.26 -54.499 L 345.009 -49.829 C 345.297 -49.547 345.758 -49.547 346.045 -49.829 L 354.62 -58.261 L 361.076 -51.914 L 361.076 -45.236 C 361.076 -44.359 360.345 -43.641 359.453 -43.641 Z M 336.326 -69.572 L 359.453 -69.572 C 360.345 -69.572 361.076 -68.854 361.076 -67.977 L 361.076 -53.957 L 355.135 -59.792 C 354.848 -60.075 354.387 -60.075 354.099 -59.792 L 345.524 -51.36 L 340.775 -56.029 C 340.488 -56.312 340.027 -56.312 339.739 -56.029 L 334.703 -51.077 L 334.703 -67.977 C 334.703 -68.854 335.434 -69.572 336.326 -69.572 Z" style="fill: rgb(175, 110, 36);" transform="matrix(0.9999999999999999, 0, 0, 0.9999999999999999, 0, -1.1368683772161603e-13)"/>
+  <path d="M 341.32 -59.468 C 343.38 -59.468 345.051 -61.117 345.051 -63.137 C 345.051 -65.156 343.374 -66.805 341.32 -66.805 C 339.266 -66.805 337.59 -65.156 337.59 -63.137 C 337.59 -61.117 339.26 -59.468 341.32 -59.468 Z M 341.32 -65.362 C 342.572 -65.362 343.584 -64.361 343.584 -63.137 C 343.584 -61.912 342.566 -60.911 341.32 -60.911 C 340.075 -60.911 339.057 -61.912 339.057 -63.137 C 339.057 -64.361 340.069 -65.362 341.32 -65.362 Z" style="fill: rgb(175, 110, 36);" transform="matrix(0.9999999999999999, 0, 0, 0.9999999999999999, 0, -1.1368683772161603e-13)"/>
+  <path d="M 333.305 13.146 C 333.305 14.824 334.694 16.184 336.395 16.184 L 359.522 16.184 C 361.229 16.184 362.612 14.818 362.612 13.146 L 362.612 -9.594 C 362.612 -11.272 361.223 -12.633 359.522 -12.633 L 336.395 -12.633 C 334.688 -12.633 333.305 -11.267 333.305 -9.594 C 333.305 -9.594 333.305 13.146 333.305 13.146 Z M 359.522 14.742 L 336.395 14.742 C 335.503 14.742 334.772 14.023 334.772 13.146 L 334.772 9.348 L 340.329 3.884 L 345.078 8.553 C 345.366 8.836 345.827 8.836 346.114 8.553 L 354.69 0.121 L 361.145 6.469 L 361.145 13.146 C 361.145 14.023 360.415 14.742 359.522 14.742 Z M 336.395 -11.19 L 359.522 -11.19 C 360.415 -11.19 361.145 -10.472 361.145 -9.594 L 361.145 4.426 L 355.205 -1.41 C 354.917 -1.692 354.456 -1.692 354.169 -1.41 L 345.593 7.022 L 340.844 2.353 C 340.557 2.07 340.096 2.07 339.809 2.353 L 334.772 7.305 L 334.772 -9.594 C 334.772 -10.472 335.503 -11.19 336.395 -11.19 Z" style="fill: rgb(175, 110, 36);" transform="matrix(0.9999999999999999, 0, 0, 0.9999999999999999, 0, -1.1368683772161603e-13)"/>
+  <path d="M 341.39 -1.086 C 343.45 -1.086 345.12 -2.735 345.12 -4.754 C 345.12 -6.774 343.444 -8.423 341.39 -8.423 C 339.335 -8.423 337.659 -6.774 337.659 -4.754 C 337.659 -2.735 339.329 -1.086 341.39 -1.086 Z M 341.39 -6.98 C 342.641 -6.98 343.653 -5.979 343.653 -4.754 C 343.653 -3.529 342.635 -2.528 341.39 -2.528 C 340.144 -2.528 339.126 -3.529 339.126 -4.754 C 339.126 -5.979 340.138 -6.98 341.39 -6.98 Z" style="fill: rgb(175, 110, 36);" transform="matrix(0.9999999999999999, 0, 0, 0.9999999999999999, 0, -1.1368683772161603e-13)"/>
+</svg>
\ No newline at end of file
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-04.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-04.svg
new file mode 100644
index 000000000..1177d6580
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-04.svg
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg viewBox="-44.887 -212.944 528.054 256.516" width="540.055px" height="256.516px" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
+  <defs>
+    <style bx:fonts="Open Sans">@import url(https://fonts.googleapis.com/css2?family=Open+Sans%3Aital%2Cwght%400%2C300%3B0%2C400%3B0%2C500%3B0%2C600%3B0%2C700%3B0%2C800%3B1%2C300%3B1%2C400%3B1%2C500%3B1%2C600%3B1%2C700%3B1%2C800&amp;display=swap);</style>
+  </defs>
+  <g id="memory-user-john-admin.svg" transform="matrix(1.708757996559143, 0, 0, 1.708757996559143, -443.0394287109375, -47.168914794921875)" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1">
+    <text id="name:-&quot;John&quot;" fill="#AF6E24" font-family="PTMono-Regular, PT Mono" font-size="12" font-weight="normal" style="white-space: pre;" x="19.382" y="-93.28"><tspan x="49.382" y="36.72" style="font-size: 12px; word-spacing: 0px;">name: "John"</tspan></text>
+    <text id="Object" fill="#AF6E24" font-family="PTMono-Regular, PT Mono" font-size="14" font-weight="normal" style="white-space: pre;" x="17.598" y="-86.206"><tspan x="61.598" y="23.794" style="font-size: 14px; word-spacing: 0px;">Object</tspan></text>
+    <path id="Rectangle-1" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 40.047 -102 L 133.047 -102 L 133.047 -76 L 40.047 -76 L 40.047 -102 Z"/>
+    <text id="text-1" style="fill: rgb(172, 67, 67); font-family: PTMono-Regular, 'PT Mono'; font-size: 14px; white-space: pre;" transform="matrix(0.735667, 0, 0, 0.753868, 86.426659, 10.790039)" x="31.917" y="-40.191">admin</text>
+    <path id="path-1" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 234.068 -87.403 L 333.494 -87.403 L 333.494 -57.762 L 234.068 -57.762 L 234.068 -87.403 Z" style=""/>
+    <path id="path-2" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 336.651 -87.403 L 492.549 -87.403 L 492.549 -57.762 L 336.651 -57.762 L 336.651 -87.403 Z" style=""/>
+    <path id="path-3" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 234.068 -53.711 L 333.494 -53.711 L 333.494 -24.07 L 234.068 -24.07 L 234.068 -53.711 Z" style=""/>
+    <path id="path-4" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 336.651 -53.711 L 492.783 -53.711 L 492.783 -24.07 L 336.651 -24.07 L 336.651 -53.711 Z" style=""/>
+    <path id="path-5" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 234.189 -20.462 L 333.615 -20.462 L 333.615 9.179 L 234.189 9.179 L 234.189 -20.462 Z" style=""/>
+    <path id="path-6" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 336.791 -20.462 L 493.057 -20.462 L 493.057 9.179 L 336.791 9.179 L 336.791 -20.462 Z" style=""/>
+    <path id="path-7" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 234.068 13.088 L 333.494 13.088 L 333.494 43.59 L 234.068 43.59 L 234.068 13.088 Z" style=""/>
+    <path id="path-8" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 336.651 13.088 L 493.054 13.088 L 493.054 43.59 L 336.651 43.59 L 336.651 13.088 Z" style=""/>
+    <text id="&lt;global&gt;" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 11.5772px; font-weight: 600; line-height: 19.9484px; white-space: pre;" transform="matrix(1.374145, 0, 0, 1.314286, -102.41082, 25.040792)" x="263.861" y="-70.535">key</text>
+    <text id="text-2" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 11.5772px; font-weight: 600; line-height: 19.9484px; white-space: pre;" transform="matrix(1.374145, 0, 0, 1.314286, 13.577469, 25.203112)" x="263.861" y="-70.535">value</text>
+    <text id="text-3" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 14px; white-space: pre;" transform="matrix(1.071654, 0, 0, 1.142641, -43.57296, 46.390514)" x="263.861" y="-70.535">image-01.jpg</text>
+    <text id="text-4" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 14px; white-space: pre;" transform="matrix(1.054877, 0, 0, 1.142641, -39.02475, 80.086914)" x="263.861" y="-70.535">image-02.jpg</text>
+    <text id="text-5" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 14px; white-space: pre;" transform="matrix(1.054877, 0, 0, 1.142641, -39.468063, 113.637062)" x="263.861" y="-70.535">image-03.jpg</text>
+    <g transform="matrix(0.000041, -1, 1.521843, 0.000133, 289.017426, 2.750529)" style="transform-origin: 105.999px -35.503px;">
+      <path d="M 105.537 7.964 L 110.918 13.895 L 100.155 13.895 L 105.537 7.964 Z" style="fill-rule: nonzero; fill: rgb(172, 67, 67);" transform="matrix(1, 0, 0, -1, 0, 0)" bx:shape="triangle 100.155 7.964 10.763 5.931 0.5 0 1@87a4267a"/>
+      <g>
+        <rect x="105.024" y="-69.436" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-59.02" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-48.877" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+      </g>
+      <g transform="matrix(1, 0, 0, 1.024052, -0.03572, 31.45084)" style="">
+        <rect x="105.024" y="-69.051" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-59.02" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-48.877" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+      </g>
+    </g>
+    <text id="text-6" style="fill: rgb(172, 67, 67); font-family: 'Open Sans'; font-size: 9.73113px; font-style: italic; white-space: pre;" transform="matrix(1.038937, 0, 0, 1.142641, 69.710487, 42.749538)" x="263.861" y="-70.535">WeakRef object</text>
+    <g transform="matrix(0.441364, 0, 0, 0.412845, 420.761139, -59.372555)" style="">
+      <g>
+        <path d=" M 58.15 23.65 L 58.15 20 54.25 20 Q 50.95 20 49.35 22.2 47.75 24.4 47.75 27.7 L 47.05 41.45 Q 46.8 43.25 46.1 44.6 45.45 46.05 44.35 47.05 43.9 47.55 43.2 47.75 42.8 47.95 41.85 48.15 L 41.85 51.6 Q 42.95 51.8 43.2 51.9 43.9 52.1 44.35 52.45 45.45 53.25 46.05 54.55 47.65 58.15 47.65 61.65 L 47.65 72.1 Q 47.65 75.7 49.45 77.85 51.25 80 54.1 80 L 58.15 80 58.15 76.25 55.25 76.25 Q 54.1 76.25 53.35 75.65 52.55 74.95 52.2 74 L 51.65 71.75 51.5 69.45 51.35 59.8 Q 51.35 57.55 50.8 55.8 50.15 53.65 49.65 52.8 48.8 51.5 47.9 50.8 47.05 50.1 46.1 49.75 47 49.3 47.8 48.7 48.95 47.85 49.6 46.75 50.1 45.8 50.75 43.7 51.35 41.85 51.35 39.45 L 51.55 28.05 52 25.9 Q 52.35 24.85 53.15 24.2 53.9 23.65 55.25 23.65 L 58.15 23.65 Z" style="fill: rgb(175, 110, 36);"/>
+      </g>
+    </g>
+    <g transform="matrix(-0.441364, 0, 0, -0.412845, 414.750092, -88.816727)" style="transform-origin: 50px 50px;">
+      <g>
+        <path d="M 14.392 23.65 L 14.392 20 L 10.492 20 C 8.292 20 6.659 20.733 5.592 22.2 C 4.525 23.667 3.992 25.5 3.992 27.7 L 3.292 41.45 C 3.125 42.65 2.809 43.7 2.342 44.6 C 1.909 45.567 1.325 46.383 0.592 47.05 C 0.292 47.383 -0.091 47.617 -0.558 47.75 C -0.825 47.883 -1.275 48.017 -1.908 48.15 L -1.908 51.6 C -1.175 51.733 -0.725 51.833 -0.558 51.9 C -0.091 52.033 0.292 52.217 0.592 52.45 C 1.325 52.983 1.892 53.683 2.292 54.55 C 3.359 56.95 3.892 59.317 3.892 61.65 L 3.892 72.1 C 3.892 74.5 4.492 76.417 5.692 77.85 C 6.892 79.283 8.442 80 10.342 80 L 14.392 80 L 14.392 76.25 L 11.492 76.25 C 10.725 76.25 10.092 76.05 9.592 75.65 C 9.059 75.183 8.675 74.633 8.442 74 L 7.892 71.75 L 7.742 69.45 L 7.592 59.8 C 7.592 58.3 7.409 56.967 7.042 55.8 C 6.609 54.367 6.225 53.367 5.892 52.8 C 5.325 51.933 4.742 51.267 4.142 50.8 C 3.575 50.333 2.975 49.983 2.342 49.75 C 2.942 49.45 3.509 49.1 4.042 48.7 C 4.809 48.133 5.409 47.483 5.842 46.75 C 6.175 46.117 6.559 45.1 6.992 43.7 C 7.392 42.467 7.592 41.05 7.592 39.45 L 7.792 28.05 L 8.242 25.9 C 8.475 25.2 8.859 24.633 9.392 24.2 C 9.892 23.833 10.592 23.65 11.492 23.65 L 14.392 23.65 Z" style="fill: rgb(175, 110, 36);"/>
+        <path d="M 255.632 27.46 L 268.667 47.91 L 242.597 47.91 L 255.632 27.46 Z" style="fill-rule: nonzero; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, 1, 0.000093, 86.522967, -302.258205)" bx:shape="triangle 242.597 27.46 26.07 20.45 0.5 0 1@97f9cc39"/>
+        <rect x="254.391" y="-239.419" width="4.82" height="17.271" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, 86.522728, -302.258331)"/>
+        <rect x="254.367" y="-203.504" width="4.82" height="17.271" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, 86.522728, -302.258331)"/>
+        <rect x="254.367" y="-168.53" width="4.82" height="17.271" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, 86.522728, -302.258331)"/>
+        <rect x="254.391" y="-243.818" width="4.82" height="17.687" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, -21.921179, -302.35498)"/>
+        <rect x="254.367" y="-208.398" width="4.82" height="17.687" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, -21.921179, -302.35498)"/>
+        <rect x="254.367" y="-172.584" width="4.82" height="17.687" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, -21.921179, -302.35498)"/>
+        <text id="text-7" style="fill: rgb(172, 67, 67); font-family: 'Open Sans'; font-size: 9.73113px; font-style: italic; white-space: pre;" transform="matrix(-2.353923, 0, 0, -2.767724, 945.975708, -228.376572)" x="263.861" y="-70.535">WeakRef object</text>
+        <path d="M 108.749 -57.365 L 108.749 -61.015 L 104.849 -61.015 C 102.649 -61.015 101.015 -60.281 99.949 -58.815 C 98.882 -57.348 98.349 -55.515 98.349 -53.315 L 97.649 -39.565 C 97.482 -38.365 97.165 -37.315 96.699 -36.415 C 96.265 -35.448 95.682 -34.631 94.949 -33.965 C 94.649 -33.631 94.265 -33.398 93.799 -33.265 C 93.532 -33.131 93.082 -32.998 92.449 -32.865 L 92.449 -29.415 C 93.182 -29.281 93.632 -29.181 93.799 -29.115 C 94.265 -28.981 94.649 -28.798 94.949 -28.565 C 95.682 -28.031 96.249 -27.331 96.649 -26.465 C 97.715 -24.065 98.249 -21.698 98.249 -19.365 L 98.249 -8.915 C 98.249 -6.515 98.849 -4.598 100.049 -3.165 C 101.249 -1.731 102.799 -1.015 104.699 -1.015 L 108.749 -1.015 L 108.749 -4.765 L 105.849 -4.765 C 105.082 -4.765 104.449 -4.965 103.949 -5.365 C 103.415 -5.831 103.032 -6.381 102.799 -7.015 L 102.249 -9.265 L 102.099 -11.565 L 101.949 -21.215 C 101.949 -22.715 101.765 -24.048 101.399 -25.215 C 100.965 -26.648 100.582 -27.648 100.249 -28.215 C 99.682 -29.081 99.099 -29.748 98.499 -30.215 C 97.932 -30.681 97.332 -31.031 96.699 -31.265 C 97.299 -31.565 97.865 -31.915 98.399 -32.315 C 99.165 -32.881 99.765 -33.531 100.199 -34.265 C 100.532 -34.898 100.915 -35.915 101.349 -37.315 C 101.749 -38.548 101.949 -39.965 101.949 -41.565 L 102.149 -52.965 L 102.599 -55.115 C 102.832 -55.815 103.215 -56.381 103.749 -56.815 C 104.249 -57.181 104.949 -57.365 105.849 -57.365 L 108.749 -57.365 Z" style="fill: rgb(175, 110, 36); transform-box: fill-box; transform-origin: 50% 50%;" transform="matrix(-1, 0, 0, -1, -0.000004, -0.000028)"/>
+        <path d="M 15.325 -57.155 L 15.325 -60.805 L 11.425 -60.805 C 9.225 -60.805 7.591 -60.072 6.525 -58.605 C 5.458 -57.139 4.925 -55.305 4.925 -53.105 L 4.225 -39.355 C 4.058 -38.155 3.741 -37.105 3.275 -36.205 C 2.841 -35.239 2.258 -34.422 1.525 -33.755 C 1.225 -33.422 0.841 -33.189 0.375 -33.055 C 0.108 -32.922 -0.342 -32.789 -0.975 -32.655 L -0.975 -29.205 C -0.242 -29.072 0.208 -28.972 0.375 -28.905 C 0.841 -28.772 1.225 -28.589 1.525 -28.355 C 2.258 -27.822 2.825 -27.122 3.225 -26.255 C 4.291 -23.855 4.825 -21.489 4.825 -19.155 L 4.825 -8.705 C 4.825 -6.305 5.425 -4.389 6.625 -2.955 C 7.825 -1.522 9.375 -0.805 11.275 -0.805 L 15.325 -0.805 L 15.325 -4.555 L 12.425 -4.555 C 11.658 -4.555 11.025 -4.755 10.525 -5.155 C 9.991 -5.622 9.608 -6.172 9.375 -6.805 L 8.825 -9.055 L 8.675 -11.355 L 8.525 -21.005 C 8.525 -22.505 8.341 -23.839 7.975 -25.005 C 7.541 -26.439 7.158 -27.439 6.825 -28.005 C 6.258 -28.872 5.675 -29.539 5.075 -30.005 C 4.508 -30.472 3.908 -30.822 3.275 -31.055 C 3.875 -31.355 4.441 -31.705 4.975 -32.105 C 5.741 -32.672 6.341 -33.322 6.775 -34.055 C 7.108 -34.689 7.491 -35.705 7.925 -37.105 C 8.325 -38.339 8.525 -39.755 8.525 -41.355 L 8.725 -52.755 L 9.175 -54.905 C 9.408 -55.605 9.791 -56.172 10.325 -56.605 C 10.825 -56.972 11.525 -57.155 12.425 -57.155 L 15.325 -57.155 Z" style="fill: rgb(175, 110, 36);"/>
+      </g>
+    </g>
+    <text id="text-9" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 4.89804px; font-weight: 700; line-height: 19.9484px; white-space: pre;" transform="matrix(1.374145, 0, 0, 1.314286, 83.283821, 89.215279)" x="263.861" y="-70.535">undefined</text>
+    <text id="text-10" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 4.89804px; font-weight: 700; line-height: 19.9484px; white-space: pre;" transform="matrix(1.374145, 0, 0, 1.314286, 82.957924, 122.90126)" x="263.861" y="-70.535">undefined</text>
+  </g>
+  <g transform="matrix(0.3355039954185486, 0, 0, 0.3355039954185486, 67.31304168701172, -387.90008544921875)" style="">
+    <g transform="matrix(0.178489, 0, 0, 0.175502, 747.077209, 776.317017)" style="">
+      <path d="M 267.184 437.8 C 267.184 466.3 290.384 489.4 318.784 489.4 L 704.984 489.4 C 733.484 489.4 756.584 466.2 756.584 437.8 L 756.584 51.6 C 756.584 23.1 733.384 0 704.984 0 L 318.784 0 C 290.284 0 267.184 23.2 267.184 51.6 C 267.184 51.6 267.184 437.8 267.184 437.8 Z M 704.984 464.9 L 318.784 464.9 C 303.884 464.9 291.684 452.7 291.684 437.8 L 291.684 373.3 L 384.484 280.5 L 463.784 359.8 C 468.584 364.6 476.284 364.6 481.084 359.8 L 624.284 216.6 L 732.084 324.4 L 732.084 437.8 C 732.084 452.7 719.884 464.9 704.984 464.9 Z M 318.784 24.5 L 704.984 24.5 C 719.884 24.5 732.084 36.7 732.084 51.6 L 732.084 289.7 L 632.884 190.6 C 628.084 185.8 620.384 185.8 615.584 190.6 L 472.384 333.8 L 393.084 254.5 C 388.284 249.7 380.584 249.7 375.784 254.5 L 291.684 338.6 L 291.684 51.6 C 291.684 36.7 303.884 24.5 318.784 24.5 Z" style="fill: rgb(175, 110, 36);"/>
+      <path d="M 418.884 196.1 C 453.284 196.1 481.184 168.1 481.184 133.8 C 481.184 99.5 453.184 71.5 418.884 71.5 C 384.584 71.5 356.584 99.5 356.584 133.8 C 356.584 168.1 384.484 196.1 418.884 196.1 Z M 418.884 96 C 439.784 96 456.684 113 456.684 133.8 C 456.684 154.6 439.684 171.6 418.884 171.6 C 398.084 171.6 381.084 154.6 381.084 133.8 C 381.084 113 397.984 96 418.884 96 Z" style="fill: rgb(175, 110, 36);"/>
+    </g>
+  </g>
+  <path d="M -161.945 -20.71 L -152.75 -5.287 L -171.141 -5.287 L -161.945 -20.71 Z" style="fill-rule: nonzero; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, -1, -0.00008700000762473792, 281.66448974609375, -149.3444061279297)" bx:shape="triangle -171.141 -20.71 18.391 15.423 0.5 0 1@d86e5ee8"/>
+  <rect x="179.461" y="-180.566" width="3.4" height="13.026" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, 1, 0.00008700000762473792, 323.07061767578125, 192.94052124023438)"/>
+  <rect x="179.444" y="-153.479" width="3.4" height="13.026" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, 1, 0.00008700000762473792, 323.07061767578125, 192.94052124023438)"/>
+  <rect x="179.444" y="-127.103" width="3.4" height="13.026" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, 1, 0.00008700000762473792, 323.07061767578125, 192.94052124023438)"/>
+  <rect x="179.461" y="-183.883" width="3.4" height="13.339" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, 1, 0.00008700000762473792, 404.8572998046875, 193.0087127685547)"/>
+  <rect x="179.444" y="-157.171" width="3.4" height="13.339" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, 1, 0.00008700000762473792, 404.8572998046875, 193.0087127685547)"/>
+  <rect x="179.444" y="-130.16" width="3.4" height="13.339" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, 1, 0.00008700000762473792, 404.8572998046875, 193.0087127685547)"/>
+  <text id="text-8" style="fill: rgb(172, 67, 67); font-family: 'Open Sans'; font-size: 9.73113px; font-style: italic; white-space: pre;" transform="matrix(1.775291919708252, 0, 0, 1.9524970054626465, -325.1152648925781, 140.8204803466797)" x="263.861" y="-70.535">WeakRef object</text>
+  <path d="M 318.601 -16.998 L 318.601 -19.573 L 315.66 -19.573 C 314.001 -19.573 312.769 -19.055 311.964 -18.021 C 311.16 -16.986 310.758 -15.693 310.758 -14.141 L 310.23 -4.441 C 310.104 -3.594 309.865 -2.853 309.513 -2.218 C 309.186 -1.536 308.746 -0.96 308.193 -0.49 C 307.967 -0.255 307.678 -0.09 307.326 0.004 C 307.125 0.098 306.786 0.192 306.308 0.286 L 306.308 2.72 C 306.861 2.814 307.2 2.884 307.326 2.931 C 307.678 3.025 307.967 3.155 308.193 3.319 C 308.746 3.696 309.174 4.189 309.475 4.801 C 310.28 6.494 310.682 8.163 310.682 9.81 L 310.682 17.181 C 310.682 18.875 311.135 20.227 312.04 21.238 C 312.945 22.249 314.114 22.755 315.547 22.755 L 318.601 22.755 L 318.601 20.109 L 316.414 20.109 C 315.836 20.109 315.358 19.968 314.981 19.686 C 314.579 19.357 314.29 18.969 314.114 18.522 L 313.699 16.935 L 313.586 15.312 L 313.473 8.504 C 313.473 7.446 313.334 6.506 313.058 5.683 C 312.731 4.671 312.442 3.966 312.191 3.566 C 311.763 2.955 311.323 2.485 310.871 2.155 C 310.443 1.826 309.991 1.579 309.513 1.415 C 309.966 1.203 310.393 0.956 310.795 0.674 C 311.373 0.274 311.826 -0.184 312.153 -0.702 C 312.404 -1.148 312.693 -1.866 313.02 -2.853 C 313.322 -3.723 313.473 -4.723 313.473 -5.852 L 313.623 -13.894 L 313.963 -15.41 C 314.139 -15.904 314.428 -16.304 314.83 -16.61 C 315.207 -16.868 315.735 -16.998 316.414 -16.998 L 318.601 -16.998 Z" style="fill: rgb(175, 110, 36);"/>
+  <path d="M 389.058 -17.145 L 389.058 -19.72 L 386.117 -19.72 C 384.458 -19.72 383.226 -19.203 382.421 -18.168 C 381.617 -17.134 381.215 -15.84 381.215 -14.288 L 380.687 -4.588 C 380.561 -3.742 380.322 -3.001 379.97 -2.366 C 379.644 -1.684 379.204 -1.108 378.651 -0.638 C 378.424 -0.403 378.135 -0.238 377.783 -0.144 C 377.582 -0.05 377.243 0.044 376.765 0.138 L 376.765 2.572 C 377.318 2.666 377.658 2.737 377.783 2.784 C 378.135 2.878 378.424 3.007 378.651 3.172 C 379.204 3.548 379.631 4.042 379.933 4.653 C 380.737 6.346 381.139 8.016 381.139 9.662 L 381.139 17.034 C 381.139 18.727 381.592 20.079 382.497 21.09 C 383.402 22.101 384.571 22.607 386.004 22.607 L 389.058 22.607 L 389.058 19.961 L 386.871 19.961 C 386.293 19.961 385.815 19.82 385.438 19.538 C 385.036 19.209 384.747 18.821 384.571 18.374 L 384.156 16.787 L 384.043 15.164 L 383.93 8.357 C 383.93 7.299 383.792 6.358 383.515 5.535 C 383.188 4.524 382.899 3.818 382.648 3.419 C 382.22 2.807 381.78 2.337 381.328 2.008 C 380.901 1.679 380.448 1.432 379.97 1.267 C 380.423 1.055 380.85 0.808 381.253 0.526 C 381.831 0.127 382.283 -0.332 382.61 -0.849 C 382.861 -1.296 383.151 -2.013 383.477 -3.001 C 383.779 -3.871 383.93 -4.87 383.93 -5.999 L 384.081 -14.041 L 384.42 -15.558 C 384.596 -16.052 384.885 -16.452 385.287 -16.757 C 385.664 -17.016 386.192 -17.145 386.871 -17.145 L 389.058 -17.145 Z" style="fill: rgb(175, 110, 36); transform-origin: 382.912px 1.4435px;" transform="matrix(-1, 0, 0, -1, 0, -0.000015020371)"/>
+</svg>
\ No newline at end of file
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-05.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-05.svg
new file mode 100644
index 000000000..e738f8e7e
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-05.svg
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg viewBox="-56.888 -599965.495 896063.875 604140.645" width="420.466px" height="300.516px" xmlns="http://www.w3.org/2000/svg" xmlns:bx="https://boxy-svg.com">
+  <defs>
+    <style bx:fonts="Open Sans">@import url(https://fonts.googleapis.com/css2?family=Open+Sans%3Aital%2Cwght%400%2C300%3B0%2C400%3B0%2C500%3B0%2C600%3B0%2C700%3B0%2C800%3B1%2C300%3B1%2C400%3B1%2C500%3B1%2C600%3B1%2C700%3B1%2C800&amp;display=swap);</style>
+  </defs>
+  <g id="memory-user-john-admin.svg" transform="matrix(3405.68798828125, 0, 0, 3405.68798828125, -789862.25, -296077.03124999994)" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1" style="">
+    <path id="path-1" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 234.068 -87.403 L 333.494 -87.403 L 333.494 -57.762 L 234.068 -57.762 L 234.068 -87.403 Z" style=""/>
+    <path id="path-2" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 336.651 -87.403 L 492.549 -87.403 L 492.549 -57.762 L 336.651 -57.762 L 336.651 -87.403 Z" style=""/>
+    <path id="path-3" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 234.068 -53.711 L 333.494 -53.711 L 333.494 -24.07 L 234.068 -24.07 L 234.068 -53.711 Z" style=""/>
+    <path id="path-4" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 336.651 -53.711 L 492.783 -53.711 L 492.783 -24.07 L 336.651 -24.07 L 336.651 -53.711 Z" style=""/>
+    <g transform="matrix(1, 0, 0, 1, 0, 42.135864)">
+      <path id="path-5" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 234.189 -20.462 L 333.615 -20.462 L 333.615 9.179 L 234.189 9.179 L 234.189 -20.462 Z" style=""/>
+      <path id="path-6" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 336.791 -20.462 L 493.057 -20.462 L 493.057 9.179 L 336.791 9.179 L 336.791 -20.462 Z" style=""/>
+      <path id="path-7" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 234.068 13.088 L 333.494 13.088 L 333.494 43.59 L 234.068 43.59 L 234.068 13.088 Z" style=""/>
+      <path id="path-8" fill="#FBF2EC" stroke="#DBAF88" stroke-width="2" d="M 336.651 13.088 L 493.054 13.088 L 493.054 43.59 L 336.651 43.59 L 336.651 13.088 Z" style=""/>
+      <text id="text-4" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 14px; white-space: pre;" transform="matrix(1.054877, 0, 0, 1.142641, -39.02475, 80.086914)" x="263.861" y="-70.535">image-02.jpg</text>
+      <text id="text-5" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 14px; white-space: pre;" transform="matrix(1.054877, 0, 0, 1.142641, -39.468063, 113.637062)" x="263.861" y="-70.535">image-03.jpg</text>
+    </g>
+    <text id="&lt;global&gt;" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 11.5772px; font-weight: 600; line-height: 19.9484px; white-space: pre;" transform="matrix(1.374145, 0, 0, 1.314286, -102.41082, 25.040792)" x="263.861" y="-70.535">key</text>
+    <text id="text-2" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 11.5772px; font-weight: 600; line-height: 19.9484px; white-space: pre;" transform="matrix(1.374145, 0, 0, 1.314286, 13.577469, 25.203112)" x="263.861" y="-70.535">value</text>
+    <text id="text-3" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 14px; white-space: pre;" transform="matrix(1.071654, 0, 0, 1.142641, -43.57296, 46.390514)" x="263.861" y="-70.535">image-01.jpg</text>
+    <g transform="matrix(0.000041, -1, 1.521843, 0.000133, 289.017426, 2.750529)" style="transform-origin: 105.999px -35.503px;">
+      <path d="M 105.537 7.964 L 110.918 13.895 L 100.155 13.895 L 105.537 7.964 Z" style="fill-rule: nonzero; fill: rgb(172, 67, 67);" transform="matrix(1, 0, 0, -1, 0, 0)" bx:shape="triangle 100.155 7.964 10.763 5.931 0.5 0 1@87a4267a"/>
+      <g>
+        <rect x="105.024" y="-69.436" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-59.02" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-48.877" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <g transform="matrix(1, 0, 0, 1, 10.348016, -60.719521)"/>
+        <g transform="matrix(1, 0, 0, 1, 10.356147, 0.41661)"/>
+        <g transform="matrix(1, 0, 0, 1, 10.161898, 52.045895)"/>
+        <g transform="matrix(1, 0, 0, 1, -23.594774, -60.719116)">
+          <rect x="79.597" y="-80.351" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.587" y="-69.935" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.587" y="-59.792" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.561" y="-50.176" width="1.99" height="5.129" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.551" y="-39.904" width="1.99" height="5.129" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.551" y="-29.517" width="1.99" height="5.129" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        </g>
+        <g transform="matrix(1, 0, 0, 1, -23.586773, 0.417928)">
+          <rect x="79.597" y="-80.351" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.587" y="-69.935" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.587" y="-59.792" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.561" y="-50.176" width="1.99" height="5.129" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.551" y="-39.904" width="1.99" height="5.129" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        </g>
+        <g transform="matrix(1, 0, 0, 1, -23.780775, 52.046886)">
+          <rect x="79.798" y="-80.298" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.587" y="-69.935" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.587" y="-59.792" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.561" y="-50.176" width="1.99" height="5.129" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.551" y="-39.904" width="1.99" height="5.129" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+          <rect x="79.551" y="-29.517" width="1.99" height="5.129" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        </g>
+      </g>
+      <g transform="matrix(1, 0, 0, 1.024052, -0.03572, 31.45084)" style="">
+        <rect x="105.024" y="-69.051" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-59.02" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+        <rect x="105.014" y="-48.877" width="1.99" height="5.009" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);"/>
+      </g>
+    </g>
+    <text id="text-6" style="fill: rgb(172, 67, 67); font-family: 'Open Sans'; font-size: 9.73113px; font-style: italic; white-space: pre;" transform="matrix(1.038937, 0, 0, 1.142641, 69.710487, 42.749538)" x="263.861" y="-70.535">WeakRef object</text>
+    <g transform="matrix(0.441364, 0, 0, 0.412845, 420.761139, -59.372555)" style="">
+      <g>
+        <path d=" M 58.15 23.65 L 58.15 20 54.25 20 Q 50.95 20 49.35 22.2 47.75 24.4 47.75 27.7 L 47.05 41.45 Q 46.8 43.25 46.1 44.6 45.45 46.05 44.35 47.05 43.9 47.55 43.2 47.75 42.8 47.95 41.85 48.15 L 41.85 51.6 Q 42.95 51.8 43.2 51.9 43.9 52.1 44.35 52.45 45.45 53.25 46.05 54.55 47.65 58.15 47.65 61.65 L 47.65 72.1 Q 47.65 75.7 49.45 77.85 51.25 80 54.1 80 L 58.15 80 58.15 76.25 55.25 76.25 Q 54.1 76.25 53.35 75.65 52.55 74.95 52.2 74 L 51.65 71.75 51.5 69.45 51.35 59.8 Q 51.35 57.55 50.8 55.8 50.15 53.65 49.65 52.8 48.8 51.5 47.9 50.8 47.05 50.1 46.1 49.75 47 49.3 47.8 48.7 48.95 47.85 49.6 46.75 50.1 45.8 50.75 43.7 51.35 41.85 51.35 39.45 L 51.55 28.05 52 25.9 Q 52.35 24.85 53.15 24.2 53.9 23.65 55.25 23.65 L 58.15 23.65 Z" style="fill: rgb(175, 110, 36);"/>
+      </g>
+    </g>
+    <g transform="matrix(-0.441364, 0, 0, -0.412845, 414.750092, -88.816727)" style="transform-origin: 50px 50px;">
+      <g>
+        <path d="M 14.392 23.65 L 14.392 20 L 10.492 20 C 8.292 20 6.659 20.733 5.592 22.2 C 4.525 23.667 3.992 25.5 3.992 27.7 L 3.292 41.45 C 3.125 42.65 2.809 43.7 2.342 44.6 C 1.909 45.567 1.325 46.383 0.592 47.05 C 0.292 47.383 -0.091 47.617 -0.558 47.75 C -0.825 47.883 -1.275 48.017 -1.908 48.15 L -1.908 51.6 C -1.175 51.733 -0.725 51.833 -0.558 51.9 C -0.091 52.033 0.292 52.217 0.592 52.45 C 1.325 52.983 1.892 53.683 2.292 54.55 C 3.359 56.95 3.892 59.317 3.892 61.65 L 3.892 72.1 C 3.892 74.5 4.492 76.417 5.692 77.85 C 6.892 79.283 8.442 80 10.342 80 L 14.392 80 L 14.392 76.25 L 11.492 76.25 C 10.725 76.25 10.092 76.05 9.592 75.65 C 9.059 75.183 8.675 74.633 8.442 74 L 7.892 71.75 L 7.742 69.45 L 7.592 59.8 C 7.592 58.3 7.409 56.967 7.042 55.8 C 6.609 54.367 6.225 53.367 5.892 52.8 C 5.325 51.933 4.742 51.267 4.142 50.8 C 3.575 50.333 2.975 49.983 2.342 49.75 C 2.942 49.45 3.509 49.1 4.042 48.7 C 4.809 48.133 5.409 47.483 5.842 46.75 C 6.175 46.117 6.559 45.1 6.992 43.7 C 7.392 42.467 7.592 41.05 7.592 39.45 L 7.792 28.05 L 8.242 25.9 C 8.475 25.2 8.859 24.633 9.392 24.2 C 9.892 23.833 10.592 23.65 11.492 23.65 L 14.392 23.65 Z" style="fill: rgb(175, 110, 36);"/>
+        <path d="M 255.632 27.46 L 268.667 47.91 L 242.597 47.91 L 255.632 27.46 Z" style="fill-rule: nonzero; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, 1, 0.000093, 86.522967, -404.320629)" bx:shape="triangle 242.597 27.46 26.07 20.45 0.5 0 1@97f9cc39"/>
+        <rect x="254.391" y="-239.419" width="4.82" height="17.271" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, 86.522728, -404.32132)"/>
+        <rect x="254.367" y="-203.504" width="4.82" height="17.271" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, 86.522728, -404.32132)"/>
+        <rect x="254.367" y="-168.53" width="4.82" height="17.271" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, 86.522728, -404.32132)"/>
+        <rect x="254.391" y="-243.818" width="4.82" height="17.687" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, -21.921179, -404.417969)"/>
+        <rect x="254.367" y="-208.398" width="4.82" height="17.687" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, -21.921179, -404.417969)"/>
+        <rect x="254.367" y="-172.584" width="4.82" height="17.687" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(-0.000038, 1, -1, -0.000093, -21.921179, -404.417969)"/>
+        <text id="text-7" style="fill: rgb(172, 67, 67); font-family: 'Open Sans'; font-size: 9.73113px; font-style: italic; white-space: pre;" transform="matrix(-2.353923, 0, 0, -2.767724, 945.975708, -330.43927)" x="263.861" y="-70.535">WeakRef object</text>
+        <path d="M 108.749 -159.455 L 108.749 -163.105 L 104.849 -163.105 C 102.649 -163.105 101.015 -162.371 99.949 -160.905 C 98.882 -159.438 98.349 -157.605 98.349 -155.405 L 97.649 -141.655 C 97.482 -140.455 97.165 -139.405 96.699 -138.505 C 96.265 -137.538 95.682 -136.721 94.949 -136.055 C 94.649 -135.721 94.265 -135.488 93.799 -135.355 C 93.532 -135.221 93.082 -135.088 92.449 -134.955 L 92.449 -131.505 C 93.182 -131.371 93.632 -131.271 93.799 -131.205 C 94.265 -131.071 94.649 -130.888 94.949 -130.655 C 95.682 -130.121 96.249 -129.421 96.649 -128.555 C 97.715 -126.155 98.249 -123.788 98.249 -121.455 L 98.249 -111.005 C 98.249 -108.605 98.849 -106.688 100.049 -105.255 C 101.249 -103.821 102.799 -103.105 104.699 -103.105 L 108.749 -103.105 L 108.749 -106.855 L 105.849 -106.855 C 105.082 -106.855 104.449 -107.055 103.949 -107.455 C 103.415 -107.921 103.032 -108.471 102.799 -109.105 L 102.249 -111.355 L 102.099 -113.655 L 101.949 -123.305 C 101.949 -124.805 101.765 -126.138 101.399 -127.305 C 100.965 -128.738 100.582 -129.738 100.249 -130.305 C 99.682 -131.171 99.099 -131.838 98.499 -132.305 C 97.932 -132.771 97.332 -133.121 96.699 -133.355 C 97.299 -133.655 97.865 -134.005 98.399 -134.405 C 99.165 -134.971 99.765 -135.621 100.199 -136.355 C 100.532 -136.988 100.915 -138.005 101.349 -139.405 C 101.749 -140.638 101.949 -142.055 101.949 -143.655 L 102.149 -155.055 L 102.599 -157.205 C 102.832 -157.905 103.215 -158.471 103.749 -158.905 C 104.249 -159.271 104.949 -159.455 105.849 -159.455 L 108.749 -159.455 Z" style="fill: rgb(175, 110, 36); transform-box: fill-box; transform-origin: 50% 50%;" transform="matrix(-1, 0, 0, -1, -0.000041, -0.000044)"/>
+        <path d="M 15.325 -159.251 L 15.325 -162.901 L 11.425 -162.901 C 9.225 -162.901 7.591 -162.168 6.525 -160.701 C 5.458 -159.235 4.925 -157.401 4.925 -155.201 L 4.225 -141.451 C 4.058 -140.251 3.741 -139.201 3.275 -138.301 C 2.841 -137.335 2.258 -136.518 1.525 -135.851 C 1.225 -135.518 0.841 -135.285 0.375 -135.151 C 0.108 -135.018 -0.342 -134.885 -0.975 -134.751 L -0.975 -131.301 C -0.242 -131.168 0.208 -131.068 0.375 -131.001 C 0.841 -130.868 1.225 -130.685 1.525 -130.451 C 2.258 -129.918 2.825 -129.218 3.225 -128.351 C 4.291 -125.951 4.825 -123.585 4.825 -121.251 L 4.825 -110.801 C 4.825 -108.401 5.425 -106.485 6.625 -105.051 C 7.825 -103.618 9.375 -102.901 11.275 -102.901 L 15.325 -102.901 L 15.325 -106.651 L 12.425 -106.651 C 11.658 -106.651 11.025 -106.851 10.525 -107.251 C 9.991 -107.718 9.608 -108.268 9.375 -108.901 L 8.825 -111.151 L 8.675 -113.451 L 8.525 -123.101 C 8.525 -124.601 8.341 -125.935 7.975 -127.101 C 7.541 -128.535 7.158 -129.535 6.825 -130.101 C 6.258 -130.968 5.675 -131.635 5.075 -132.101 C 4.508 -132.568 3.908 -132.918 3.275 -133.151 C 3.875 -133.451 4.441 -133.801 4.975 -134.201 C 5.741 -134.768 6.341 -135.418 6.775 -136.151 C 7.108 -136.785 7.491 -137.801 7.925 -139.201 C 8.325 -140.435 8.525 -141.851 8.525 -143.451 L 8.725 -154.851 L 9.175 -157.001 C 9.408 -157.701 9.791 -158.268 10.325 -158.701 C 10.825 -159.068 11.525 -159.251 12.425 -159.251 L 15.325 -159.251 Z" style="fill: rgb(175, 110, 36);"/>
+      </g>
+    </g>
+    <text id="text-9" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 4.89804px; font-weight: 700; line-height: 19.9484px; white-space: pre;" transform="matrix(1.374145, 0, 0, 1.314286, 83.283821, 131.351151)" x="263.861" y="-70.535">undefined</text>
+    <text id="text-10" style="fill: rgb(175, 110, 36); font-family: 'Open Sans'; font-size: 4.89804px; font-weight: 700; line-height: 19.9484px; white-space: pre;" transform="matrix(1.374145, 0, 0, 1.314286, 82.957924, 165.037125)" x="263.861" y="-70.535">undefined</text>
+    <text id="text-11" style="fill: rgb(172, 67, 67); font-family: 'Open Sans'; font-size: 9.73113px; font-style: italic; white-space: pre;" transform="matrix(1.038937, 0, 0, 1.142641, -18.813889, 90.723404)" x="263.861" y="-70.535">Deleted by FinalizationRegistry cleanup callback</text>
+  </g>
+  <g transform="matrix(668.68603515625, 0, 0, 668.68603515625, 227309.90625, -975180.6875)" style="">
+    <g transform="matrix(0.178489, 0, 0, 0.175502, 747.077209, 776.317017)" style="">
+      <path d="M 267.184 437.8 C 267.184 466.3 290.384 489.4 318.784 489.4 L 704.984 489.4 C 733.484 489.4 756.584 466.2 756.584 437.8 L 756.584 51.6 C 756.584 23.1 733.384 0 704.984 0 L 318.784 0 C 290.284 0 267.184 23.2 267.184 51.6 C 267.184 51.6 267.184 437.8 267.184 437.8 Z M 704.984 464.9 L 318.784 464.9 C 303.884 464.9 291.684 452.7 291.684 437.8 L 291.684 373.3 L 384.484 280.5 L 463.784 359.8 C 468.584 364.6 476.284 364.6 481.084 359.8 L 624.284 216.6 L 732.084 324.4 L 732.084 437.8 C 732.084 452.7 719.884 464.9 704.984 464.9 Z M 318.784 24.5 L 704.984 24.5 C 719.884 24.5 732.084 36.7 732.084 51.6 L 732.084 289.7 L 632.884 190.6 C 628.084 185.8 620.384 185.8 615.584 190.6 L 472.384 333.8 L 393.084 254.5 C 388.284 249.7 380.584 249.7 375.784 254.5 L 291.684 338.6 L 291.684 51.6 C 291.684 36.7 303.884 24.5 318.784 24.5 Z" style="fill: rgb(175, 110, 36);"/>
+      <path d="M 418.884 196.1 C 453.284 196.1 481.184 168.1 481.184 133.8 C 481.184 99.5 453.184 71.5 418.884 71.5 C 384.584 71.5 356.584 99.5 356.584 133.8 C 356.584 168.1 384.484 196.1 418.884 196.1 Z M 418.884 96 C 439.784 96 456.684 113 456.684 133.8 C 456.684 154.6 439.684 171.6 418.884 171.6 C 398.084 171.6 381.084 154.6 381.084 133.8 C 381.084 113 397.984 96 418.884 96 Z" style="fill: rgb(175, 110, 36);"/>
+    </g>
+  </g>
+  <path d="M 359424.367 41276.336 L 377751.896 72015.889 L 341096.837 72015.889 L 359424.367 41276.336 Z" style="fill-rule: nonzero; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, -1, -0.00008700000762473792, 737054.1250000001, 325983.1250000001)" bx:shape="triangle 341096.837 41276.336 36655.059 30739.553 0.5 0 1@d50babe8"/>
+  <rect x="357681.08" y="-359881.579" width="6776.286" height="25963.08" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, 1, 0.00008700000762473792, 737054.6250000001, 325981.3125000001)"/>
+  <rect x="357644.501" y="-305895.331" width="6776.286" height="25963.08" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, 1, 0.00008700000762473792, 737054.6250000001, 325981.3125000001)"/>
+  <rect x="357644.501" y="-253326.04" width="6776.286" height="25963.08" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, 1, 0.00008700000762473792, 737054.6250000001, 325981.3125000001)"/>
+  <rect x="357681.08" y="-366492.978" width="6776.286" height="26586.395" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, 1, 0.00008700000762473792, 900061.8125000001, 326117.2187500001)"/>
+  <rect x="357644.501" y="-313254.567" width="6776.286" height="26586.395" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, 1, 0.00008700000762473792, 900061.8125000001, 326117.2187500001)"/>
+  <rect x="357644.501" y="-259418.129" width="6776.286" height="26586.395" style="paint-order: stroke; stroke: rgb(53, 81, 138); stroke-width: 0px; fill: rgb(172, 67, 67);" transform="matrix(0.00004100000296602957, -1, 1, 0.00008700000762473792, 900061.8125000001, 326117.2187500001)"/>
+  <text id="text-8" style="fill: rgb(172, 67, 67); font-family: 'Open Sans'; font-size: 9.73113px; font-style: italic; white-space: pre;" transform="matrix(3538.295166015625, 0, 0, 3891.478759765625, -554830.25, 222101.96875)" x="263.861" y="-70.535">WeakRef object</text>
+  <path d="M 728146.338 -92443.632 L 728146.338 -97574.712 L 722284.793 -97574.712 C 718978.199 -97574.712 716523.314 -96542.53 714919.193 -94480.927 C 713316.016 -92418.404 712514.341 -89841.53 712514.341 -86748.938 L 711462.052 -67415.4 C 711210.096 -65727.244 710734.892 -64250.108 710033.283 -62985.482 C 709382.304 -61626.233 708504.597 -60478.003 707402.151 -59541.042 C 706951.752 -59072.499 706375.587 -58743.915 705673.655 -58556.036 C 705273.289 -58368.007 704596.909 -58181.644 703645.158 -57993.168 L 703645.158 -53141.856 C 704747.605 -52953.853 705423.812 -52816.007 705673.655 -52721.682 C 706375.587 -52533.653 706951.752 -52275.956 707402.151 -51947.819 C 708504.597 -51196.774 709359.189 -50215.843 709957.252 -48995.062 C 711561.373 -45621.509 712363.794 -42293.888 712363.794 -39012.547 L 712363.794 -24320.941 C 712363.794 -20946.169 713265.063 -18250.364 715069.292 -16236.209 C 716874.118 -14219.916 719201.895 -13211.347 722059.73 -13211.347 L 728146.338 -13211.347 L 728146.338 -18485.095 L 723786.735 -18485.095 C 722635.597 -18485.095 721683.847 -18767.275 720932.205 -19327.881 C 720129.784 -19984.452 719554.812 -20757.843 719201.895 -21648.25 L 718377.253 -24810.511 L 718150.525 -28045.597 L 717925.463 -41615.096 C 717925.463 -43722.656 717648.726 -45597.921 717099.007 -47236.193 C 716447.133 -49254.872 715870.968 -50660.078 715370.511 -51456.161 C 714517.162 -52674.979 713641.12 -53612.089 712740.149 -54268.661 C 711885.582 -54925.978 710986.4 -55416.741 710033.283 -55743.536 C 710935.472 -56166.271 711786.261 -56657.059 712587.937 -57219.753 C 713740.267 -58016.755 714644.122 -58930.278 715294.33 -59961.987 C 715794.787 -60852.37 716371.101 -62282.655 717022.975 -64250.108 C 717625.611 -65984.196 717925.463 -67976.901 717925.463 -70227.453 L 718225.811 -86255.615 L 718902.938 -89277.444 C 719252.823 -90261.705 719829.908 -91059.9 720629.445 -91669.769 C 721380.938 -92183.673 722434.122 -92443.632 723786.735 -92443.632 L 728146.338 -92443.632 Z" style="fill: rgb(175, 110, 36);"/>
+  <path d="M 868579.948 -92734.348 L 868579.948 -97866.322 L 862717.955 -97866.322 C 859411.336 -97866.322 856954.786 -96837.173 855350.69 -94775.421 C 853747.488 -92713.793 852947.926 -90134.359 852947.926 -87041.916 L 851895.661 -67707.906 C 851643.706 -66022.185 851168.054 -64545.67 850465.228 -63278.459 C 849816.809 -61920.428 848939.872 -60773.094 847838.32 -59836.43 C 847385.039 -59366.993 846807.506 -59039.453 846107.264 -58850.977 C 845705.979 -58662.948 845032.333 -58476.734 844077.55 -58288.705 L 844077.55 -53438.165 C 845180.295 -53250.136 845856.974 -53108.363 846107.264 -53014.659 C 846807.506 -52828.296 847385.039 -52570.897 847838.32 -52242.462 C 848939.872 -51491.715 849788.996 -50508.374 850393.421 -49291.196 C 851994.957 -45916.599 852795.738 -42588.531 852795.738 -39308.084 L 852795.738 -24614.217 C 852795.738 -21238.7 853699.12 -18545.753 855503.051 -16529.485 C 857306.038 -14515.33 859635.504 -13506.885 862491.674 -13506.885 L 868579.948 -13506.885 L 868579.948 -18781.23 L 864220.319 -18781.23 C 863067.542 -18781.23 862114.424 -19061.47 861364.149 -19624.164 C 860562.474 -20278.623 859988.421 -21052.486 859635.504 -21943.639 L 858809.496 -25105.899 L 858584.135 -28341.01 L 858357.407 -41908.844 C 858357.407 -44017.15 858082.336 -45890.452 857532.617 -47532.477 C 856880.42 -49546.483 856302.887 -50953.801 855803.201 -51749.114 C 854950.299 -52969.622 854074.73 -53906.708 853171.77 -54561.937 C 852320.832 -55217.589 851420.01 -55710.191 850465.228 -56038.154 C 851368.61 -56462.579 852219.573 -56952.447 853024.106 -57514.843 C 854174.772 -58310.926 855075.594 -59225.667 855727.194 -60256.63 C 856228.546 -61147.784 856806.351 -62576.08 857456.585 -64545.67 C 858057.531 -66279.609 858357.407 -68270.177 858357.407 -70520.281 L 858660.316 -86548.145 L 859335.33 -89573.007 C 859685.662 -90557.094 860263.045 -91354.096 861063.055 -91962.3 C 861814.548 -92479.061 862866.066 -92734.348 864220.319 -92734.348 L 868579.948 -92734.348 Z" style="fill: rgb(175, 110, 36); transform-origin: 856323px -55686.3px;" transform="matrix(-1, 0, 0, -1, 0.87500000055, -0.046875000444)"/>
+  <rect x="3810.427" y="-226324.344" width="889802.927" height="226474.243" style="stroke: rgb(0, 0, 0); stroke-opacity: 0; fill: rgb(172, 67, 67); opacity: 0.76;"/>
+</svg>
\ No newline at end of file
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-01.png b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-01.png
new file mode 100644
index 000000000..fc33a023a
Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-01.png differ
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-02.png b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-02.png
new file mode 100644
index 000000000..7d8bb01e8
Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-02.png differ
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-03.gif b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-03.gif
new file mode 100644
index 000000000..b81966dda
Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-03.gif differ
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-04.jpg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-04.jpg
new file mode 100644
index 000000000..ba60f1e86
Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-04.jpg differ
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-05.gif b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-05.gif
new file mode 100644
index 000000000..d34bda4d7
Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-05.gif differ
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-06.jpg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-06.jpg
new file mode 100644
index 000000000..b2655540f
Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-06.jpg differ
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-07.gif b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-07.gif
new file mode 100644
index 000000000..51f874518
Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-07.gif differ
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-08.jpg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-08.jpg
new file mode 100644
index 000000000..5f98aec14
Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-08.jpg differ
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.css b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.css
new file mode 100644
index 000000000..e6c9e3960
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.css
@@ -0,0 +1,285 @@
+:root {
+    --mineralGreen: 60, 98, 85;
+    --viridianGreen: 97, 135, 110;
+    --swampGreen: 166, 187, 141;
+    --fallGreen: 234, 231, 177;
+    --brinkPink: #FA7070;
+    --silverChalice: 178, 178, 178;
+    --white: 255, 255, 255;
+    --black: 0, 0, 0;
+
+    --topBarHeight: 64px;
+    --itemPadding: 32px;
+    --containerGap: 8px;
+}
+
+@keyframes zoom-in {
+    0% {
+        transform: scale(1, 1);
+    }
+
+    100% {
+        transform: scale(1.30, 1.30);
+    }
+}
+
+body, html {
+    margin: 0;
+    padding: 0;
+}
+
+.app {
+    min-height: 100vh;
+    background-color: rgba(var(--viridianGreen), 0.5);
+}
+
+.header {
+    height: var(--topBarHeight);
+    padding: 0 24px;
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    background-color: rgba(var(--mineralGreen), 1);
+}
+
+.header-text {
+    color: white;
+}
+
+.container {
+    display: flex;
+    gap: 24px;
+    padding: var(--itemPadding);
+}
+
+.item {
+    width: 50%;
+}
+
+.item--scrollable {
+    overflow-y: scroll;
+    height: calc(100vh - var(--topBarHeight) - (var(--itemPadding) * 2));
+}
+
+.thumbnails-container {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 8px;
+    justify-content: center;
+    align-items: center;
+}
+
+.thumbnail-item {
+    width: calc(25% - var(--containerGap));
+    cursor: pointer;
+    position: relative;
+}
+
+.thumbnail-item:hover {
+    z-index: 1;
+    animation: zoom-in 0.1s forwards;
+}
+
+.thumbnail-item--selected {
+    outline: 3px solid rgba(var(--fallGreen), 1);
+    outline-offset: -3px;
+}
+
+.badge {
+    width: 16px;
+    height: 16px;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    padding: 4px;
+    position: absolute;
+    right: 8px;
+    bottom: 8px;
+    border-radius: 50%;
+    border: 2px solid rgba(var(--fallGreen), 1);
+    background-color: rgba(var(--swampGreen), 1);
+}
+
+.check {
+    display: inline-block;
+    transform: rotate(45deg);
+    border-bottom: 2px solid white;
+    border-right: 2px solid white;
+    width: 6px;
+    height: 12px;
+}
+
+.img {
+    width: 100%;
+    height: 100%;
+    object-fit: cover;
+}
+
+.actions {
+    display: flex;
+    flex-wrap: wrap;
+    justify-content: center;
+    align-content: center;
+    padding: 0 0 16px 0;
+    gap: 8px;
+}
+
+.select {
+    padding: 16px;
+    cursor: pointer;
+    font-weight: 700;
+    color: rgba(var(--black), 1);
+    border: 2px solid rgba(var(--swampGreen), 0.5);
+    background-color: rgba(var(--swampGreen), 1);
+}
+
+.select:disabled {
+    cursor: not-allowed;
+    background-color: rgba(var(--silverChalice), 1);
+    color: rgba(var(--black), 0.5);
+    border: 2px solid rgba(var(--black), 0.25);
+}
+
+.btn {
+    outline: none;
+    padding: 16px;
+    cursor: pointer;
+    font-weight: 700;
+    color: rgba(var(--black), 1);
+    border: 2px solid rgba(var(--black), 0.5);
+}
+
+.btn--primary {
+    background-color: rgba(var(--mineralGreen), 1);
+}
+
+.btn--primary:hover:not([disabled]) {
+    background-color: rgba(var(--mineralGreen), 0.85);
+}
+
+.btn--secondary {
+    background-color: rgba(var(--viridianGreen), 0.5);
+}
+
+.btn--secondary:hover:not([disabled]) {
+    background-color: rgba(var(--swampGreen), 0.25);
+}
+
+.btn--success {
+    background-color: rgba(var(--fallGreen), 1);
+}
+
+.btn--success:hover:not([disabled]) {
+    background-color: rgba(var(--fallGreen), 0.85);
+}
+
+.btn:disabled {
+    cursor: not-allowed;
+    background-color: rgba(var(--silverChalice), 1);
+    color: rgba(var(--black), 0.5);
+    border: 2px solid rgba(var(--black), 0.25);
+}
+
+.previewContainer {
+    margin-bottom: 16px;
+    display: flex;
+    width: 100%;
+    height: 40vh;
+    overflow: scroll;
+    border: 3px solid rgba(var(--black), 1);
+}
+
+.previewContainer--disabled {
+    background-color: rgba(var(--black), 0.1);
+    cursor: not-allowed;
+}
+
+.canvas {
+    margin: auto;
+    display: none;
+}
+
+.canvas--ready {
+    display: block;
+}
+
+.spinnerContainer {
+    display: flex;
+    gap: 8px;
+    flex-direction: column;
+    align-content: center;
+    align-items: center;
+    margin: auto;
+}
+
+.spinnerContainer--hidden {
+    display: none;
+}
+
+.spinnerText {
+    margin: 0;
+    color: rgba(var(--mineralGreen), 1);
+}
+
+.spinner {
+    display: inline-block;
+    width: 50px;
+    height: 50px;
+    margin: auto;
+    border: 3px solid rgba(var(--mineralGreen), 0.3);
+    border-radius: 50%;
+    border-top-color: rgba(var(--mineralGreen), 0.9);
+    animation: spin 1s ease-in-out infinite;
+}
+
+@keyframes spin {
+    to {
+        transform: rotate(360deg);
+    }
+}
+
+.loggerContainer {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+    padding: 0 8px 8px 8px;
+    width: 100%;
+    min-height: 30vh;
+    max-height: 30vh;
+    overflow: scroll;
+    border-left: 3px solid rgba(var(--black), 0.25);
+}
+
+.logger-title {
+    display: flex;
+    align-items: center;
+    padding: 8px;
+    position: sticky;
+    height: 40px;
+    min-height: 40px;
+    top: 0;
+    left: 0;
+    background-color: rgba(var(--viridianGreen), 1);
+    font-size: 24px;
+    font-weight: 700;
+    margin: 0;
+}
+
+.logger-item {
+    font-size: 14px;
+    padding: 8px;
+    border: 2px solid #5a5a5a;
+    color: white;
+}
+
+.logger--primary {
+    background-color: #13315a;
+}
+
+.logger--success {
+    background-color: #385a4e;
+}
+
+.logger--error {
+    background-color: #5a1a24;
+}
\ No newline at end of file
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.html b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.html
new file mode 100644
index 000000000..7ce52f927
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.html
@@ -0,0 +1,49 @@
+<!DOCTYPE HTML>
+<html lang="en">
+
+<head>
+  <meta charset="utf-8">
+  <link rel="stylesheet" href="index.css">
+  <title>Photo Library Collage</title>
+</head>
+
+<body>
+
+<div class="app">
+  <header class="header">
+    <h1 class="header-text">
+      Photo Library Collage
+    </h1>
+  </header>
+  <div class="container">
+    <div class="item item--scrollable">
+      <!--Thumbnails-->
+      <div class="thumbnails-container"></div>
+    </div>
+    <div class="item">
+      <div>
+        <div class=actions>
+          <select class="select"></select>
+          <button class="btn btn--primary btn-create-collage"> Create collage </button>
+          <button class="btn btn--secondary btn-start-over"> Start over </button>
+          <button class="btn btn--success btn-download" onClick={downloadCollage}> Download </button>
+        </div>
+        <div class="previewContainer">
+          <div class="spinnerContainer spinnerContainer--hidden">
+            <div class="spinner"></div>
+            <p class="spinnerText"></p>
+          </div>
+          <canvas class="canvas"></canvas>
+        </div>
+        <div class="loggerContainer">
+          <p class="logger-title">Logger:</p>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
+
+
+<script type="module" src="index.js"></script>
+</body>
+</html>
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.js b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.js
new file mode 100644
index 000000000..983b34d9a
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.js
@@ -0,0 +1,228 @@
+import {
+    createImageFile,
+    loadImage,
+    weakRefCache,
+    LAYOUTS,
+    images,
+    THUMBNAIL_PARAMS,
+    stateObj,
+} from "./utils.js";
+
+export const state = new Proxy(stateObj, {
+    set(target, property, value) {
+        const previousValue = target[property];
+
+        target[property] = value;
+
+        if (previousValue !== value) {
+            handleStateChange(target);
+        }
+
+        return true;
+    },
+});
+
+// Elements.
+const thumbnailsContainerEl = document.querySelector(".thumbnails-container");
+const selectEl = document.querySelector(".select");
+const previewContainerEl = document.querySelector(".previewContainer");
+const canvasEl = document.querySelector(".canvas");
+const createCollageBtn = document.querySelector(".btn-create-collage");
+const startOverBtn = document.querySelector(".btn-start-over");
+const downloadBtn = document.querySelector(".btn-download");
+const spinnerContainerEl = document.querySelector(".spinnerContainer");
+const spinnerTextEl = document.querySelector(".spinnerText");
+const loggerContainerEl = document.querySelector(".loggerContainer");
+
+// Renders.
+// Render thumbnails previews.
+images.forEach((img) => {
+    const thumbnail = document.createElement("div");
+    thumbnail.classList.add("thumbnail-item");
+
+    thumbnail.innerHTML = `
+        <img src='${img.img}?${THUMBNAIL_PARAMS}' class="img">
+  `;
+
+    thumbnail.addEventListener("click", (e) => handleSelection(e, img));
+
+    thumbnailsContainerEl.appendChild(thumbnail);
+});
+// Render layouts select.
+LAYOUTS.forEach((layout) => {
+    const option = document.createElement("option");
+    option.value = JSON.stringify(layout);
+    option.innerHTML = layout.name;
+    selectEl.appendChild(option);
+});
+
+const handleStateChange = (state) => {
+    if (state.loading) {
+        selectEl.disabled = true;
+        createCollageBtn.disabled = true;
+        startOverBtn.disabled = true;
+        downloadBtn.disabled = true;
+        previewContainerEl.classList.add("previewContainer--disabled");
+        spinnerContainerEl.classList.remove("spinnerContainer--hidden");
+        spinnerTextEl.innerText = "Loading...";
+        canvasEl.classList.remove("canvas--ready");
+    } else if (!state.loading) {
+        selectEl.disabled = false;
+        createCollageBtn.disabled = false;
+        startOverBtn.disabled = false;
+        downloadBtn.disabled = false;
+        previewContainerEl.classList.remove("previewContainer--disabled");
+        spinnerContainerEl.classList.add("spinnerContainer--hidden");
+        canvasEl.classList.add("canvas--ready");
+    }
+
+    if (!state.selectedImages.size) {
+        createCollageBtn.disabled = true;
+        document.querySelectorAll(".badge").forEach((item) => item.remove());
+    } else if (state.selectedImages.size && !state.loading) {
+        createCollageBtn.disabled = false;
+    }
+
+    if (!state.collageRendered) {
+        downloadBtn.disabled = true;
+    } else if (state.collageRendered) {
+        downloadBtn.disabled = false;
+    }
+};
+handleStateChange(state);
+
+const handleSelection = (e, imgName) => {
+    const imgEl = e.currentTarget;
+
+    imgEl.classList.toggle("thumbnail-item--selected");
+
+    if (state.selectedImages.has(imgName)) {
+        state.selectedImages.delete(imgName);
+        state.selectedImages = new Set(state.selectedImages);
+        imgEl.querySelector(".badge")?.remove();
+    } else {
+        state.selectedImages = new Set(state.selectedImages.add(imgName));
+
+        const badge = document.createElement("div");
+        badge.classList.add("badge");
+        badge.innerHTML = `
+            <div class="check" />
+        `;
+        imgEl.prepend(badge);
+    }
+};
+
+// Make a wrapper function.
+let getCachedImage;
+(async () => {
+    getCachedImage = await weakRefCache(loadImage);
+})();
+
+const calculateGridRows = (blobsLength) =>
+    Math.ceil(blobsLength / state.currentLayout.columns);
+
+const drawCollage = (images) => {
+    state.drawing = true;
+
+    let context = canvasEl.getContext("2d");
+
+    /**
+     * Calculate canvas dimensions based on the current layout.
+     * */
+    context.canvas.width =
+        state.currentLayout.itemWidth * state.currentLayout.columns;
+    context.canvas.height =
+        calculateGridRows(images.length) * state.currentLayout.itemHeight;
+
+    let currentRow = 0;
+    let currentCanvasDx = 0;
+    let currentCanvasDy = 0;
+
+    for (let i = 0; i < images.length; i++) {
+        /**
+         * Get current row of the collage.
+         * */
+        if (i % state.currentLayout.columns === 0) {
+            currentRow += 1;
+            currentCanvasDx = 0;
+
+            if (currentRow > 1) {
+                currentCanvasDy += state.currentLayout.itemHeight;
+            }
+        }
+
+        context.drawImage(
+            images[i],
+            0,
+            0,
+            images[i].width,
+            images[i].height,
+            currentCanvasDx,
+            currentCanvasDy,
+            state.currentLayout.itemWidth,
+            state.currentLayout.itemHeight,
+        );
+
+        currentCanvasDx += state.currentLayout.itemWidth;
+    }
+
+    state.drawing = false;
+    state.collageRendered = true;
+};
+
+const createCollage = async () => {
+    state.loading = true;
+
+    const images = [];
+
+    for (const image of state.selectedImages.values()) {
+        const blobImage = await getCachedImage(image.img);
+
+        const url = URL.createObjectURL(blobImage);
+        const img = await createImageFile(url);
+
+        images.push(img);
+        URL.revokeObjectURL(url);
+    }
+
+    state.loading = false;
+
+    drawCollage(images);
+};
+
+/**
+ * Clear all settled data to start over.
+ * */
+const startOver = () => {
+    state.selectedImages = new Set();
+    state.collageRendered = false;
+    const context = canvasEl.getContext("2d");
+    context.clearRect(0, 0, canvasEl.width, canvasEl.height);
+
+    document
+        .querySelectorAll(".thumbnail-item--selected")
+        .forEach((item) => item.classList.remove("thumbnail-item--selected"));
+
+    loggerContainerEl.innerHTML = '<p class="logger-title">Logger:</p>';
+};
+
+const downloadCollage = () => {
+    const date = new Date();
+    const fileName = `Collage-${date.getDay()}-${date.getMonth()}-${date.getFullYear()}.png`;
+    const img = canvasEl.toDataURL("image/png");
+    const link = document.createElement("a");
+    link.download = fileName;
+    link.href = img;
+    link.click();
+    link.remove();
+};
+
+const changeLayout = ({ target }) => {
+    state.currentLayout = JSON.parse(target.value);
+};
+
+// Listeners.
+selectEl.addEventListener("change", changeLayout);
+createCollageBtn.addEventListener("click", createCollage);
+startOverBtn.addEventListener("click", startOver);
+downloadBtn.addEventListener("click", downloadCollage);
diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/utils.js b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/utils.js
new file mode 100644
index 000000000..f0140c116
--- /dev/null
+++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/utils.js
@@ -0,0 +1,321 @@
+const loggerContainerEl = document.querySelector(".loggerContainer");
+
+export const images = [
+    {
+        img: "https://images.unsplash.com/photo-1471357674240-e1a485acb3e1",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1589118949245-7d38baf380d6",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1527631746610-bca00a040d60",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1500835556837-99ac94a94552",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1503220317375-aaad61436b1b",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1501785888041-af3ef285b470",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1528543606781-2f6e6857f318",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1523906834658-6e24ef2386f9",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1539635278303-d4002c07eae3",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1533105079780-92b9be482077",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1516483638261-f4dbaf036963",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1502791451862-7bd8c1df43a7",
+    },
+    {
+        img: "https://plus.unsplash.com/premium_photo-1663047367140-91adf819d007",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1506197603052-3cc9c3a201bd",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1517760444937-f6397edcbbcd",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1518684079-3c830dcef090",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1505832018823-50331d70d237",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1524850011238-e3d235c7d4c9",
+    },
+    {
+        img: "https://plus.unsplash.com/premium_photo-1661277758451-b5053309eea1",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1541410965313-d53b3c16ef17",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1528702748617-c64d49f918af",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1502003148287-a82ef80a6abc",
+    },
+    {
+        img: "https://plus.unsplash.com/premium_photo-1661281272544-5204ea3a481a",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1503457574462-bd27054394c1",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1499363536502-87642509e31b",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1551918120-9739cb430c6d",
+    },
+    {
+        img: "https://plus.unsplash.com/premium_photo-1661382219642-43e54f7e81d7",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1497262693247-aa258f96c4f5",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1525254134158-4fd5fdd45793",
+    },
+    {
+        img: "https://plus.unsplash.com/premium_photo-1661274025419-4c54107d5c48",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1553697388-94e804e2f0f6",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1574260031597-bcd9eb192b4f",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1536323760109-ca8c07450053",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1527824404775-dce343118ebc",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1612278675615-7b093b07772d",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1522010675502-c7b3888985f6",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1501555088652-021faa106b9b",
+    },
+    {
+        img: "https://plus.unsplash.com/premium_photo-1669223469435-27e091439169",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1506012787146-f92b2d7d6d96",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1511739001486-6bfe10ce785f",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1553342385-111fd6bc6ab3",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1516546453174-5e1098a4b4af",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1527142879-95b61a0b8226",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1520466809213-7b9a56adcd45",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1516939884455-1445c8652f83",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1545389336-cf090694435e",
+    },
+    {
+        img: "https://plus.unsplash.com/premium_photo-1669223469455-b7b734c838f4",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1454391304352-2bf4678b1a7a",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1433838552652-f9a46b332c40",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1506125840744-167167210587",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1522199873717-bc67b1a5e32b",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1495904786722-d2b5a19a8535",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1614094082869-cd4e4b2905c7",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1474755032398-4b0ed3b2ae5c",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1501554728187-ce583db33af7",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1515859005217-8a1f08870f59",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1531141445733-14c2eb7d4c1f",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1500259783852-0ca9ce8a64dc",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1510662145379-13537db782dc",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1573790387438-4da905039392",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1512757776214-26d36777b513",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1518855706573-84de4022b69b",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1500049242364-5f500807cdd7",
+    },
+    {
+        img: "https://images.unsplash.com/photo-1528759335187-3b683174c86a",
+    },
+];
+export const THUMBNAIL_PARAMS = "w=240&h=240&fit=crop&auto=format";
+
+// Console styles.
+export const CONSOLE_BASE_STYLES = [
+    "font-size: 12px",
+    "padding: 4px",
+    "border: 2px solid #5a5a5a",
+    "color: white",
+].join(";");
+export const CONSOLE_PRIMARY = [
+    CONSOLE_BASE_STYLES,
+    "background-color: #13315a",
+].join(";");
+export const CONSOLE_SUCCESS = [
+    CONSOLE_BASE_STYLES,
+    "background-color: #385a4e",
+].join(";");
+export const CONSOLE_ERROR = [
+    CONSOLE_BASE_STYLES,
+    "background-color: #5a1a24",
+].join(";");
+
+// Layouts.
+export const LAYOUT_4_COLUMNS = {
+    name: "Layout 4 columns",
+    columns: 4,
+    itemWidth: 240,
+    itemHeight: 240,
+};
+export const LAYOUT_8_COLUMNS = {
+    name: "Layout 8 columns",
+    columns: 8,
+    itemWidth: 240,
+    itemHeight: 240,
+};
+export const LAYOUTS = [LAYOUT_4_COLUMNS, LAYOUT_8_COLUMNS];
+
+export const createImageFile = async (src) =>
+    new Promise((resolve, reject) => {
+        const img = new Image();
+        img.src = src;
+        img.onload = () => resolve(img);
+        img.onerror = () => reject(new Error("Failed to construct image."));
+    });
+
+export const loadImage = async (url) => {
+    try {
+        const response = await fetch(url);
+        if (!response.ok) {
+            throw new Error(String(response.status));
+        }
+
+        return await response.blob();
+    } catch (e) {
+        console.log(`%cFETCHED_FAILED: ${e}`, CONSOLE_ERROR);
+    }
+};
+
+export const weakRefCache = (fetchImg) => {
+    const imgCache = new Map();
+    const registry = new FinalizationRegistry(({ imgName, size, type }) => {
+        const cachedImg = imgCache.get(imgName);
+        if (cachedImg && !cachedImg.deref()) {
+            imgCache.delete(imgName);
+            console.log(
+                `%cCLEANED_IMAGE: Url: ${imgName}, Size: ${size}, Type: ${type}`,
+                CONSOLE_ERROR,
+            );
+
+            const logEl = document.createElement("div");
+            logEl.classList.add("logger-item", "logger--error");
+            logEl.innerHTML = `CLEANED_IMAGE: Url: ${imgName}, Size: ${size}, Type: ${type}`;
+            loggerContainerEl.appendChild(logEl);
+            loggerContainerEl.scrollTop = loggerContainerEl.scrollHeight;
+        }
+    });
+
+    return async (imgName) => {
+        const cachedImg = imgCache.get(imgName);
+
+        if (cachedImg?.deref() !== undefined) {
+            console.log(
+                `%cCACHED_IMAGE: Url: ${imgName}, Size: ${cachedImg.size}, Type: ${cachedImg.type}`,
+                CONSOLE_SUCCESS,
+            );
+
+            const logEl = document.createElement("div");
+            logEl.classList.add("logger-item", "logger--success");
+            logEl.innerHTML = `CACHED_IMAGE: Url: ${imgName}, Size: ${cachedImg.size}, Type: ${cachedImg.type}`;
+            loggerContainerEl.appendChild(logEl);
+            loggerContainerEl.scrollTop = loggerContainerEl.scrollHeight;
+
+            return cachedImg?.deref();
+        }
+
+        const newImg = await fetchImg(imgName);
+        console.log(
+            `%cFETCHED_IMAGE: Url: ${imgName}, Size: ${newImg.size}, Type: ${newImg.type}`,
+            CONSOLE_PRIMARY,
+        );
+
+        const logEl = document.createElement("div");
+        logEl.classList.add("logger-item", "logger--primary");
+        logEl.innerHTML = `FETCHED_IMAGE: Url: ${imgName}, Size: ${newImg.size}, Type: ${newImg.type}`;
+        loggerContainerEl.appendChild(logEl);
+        loggerContainerEl.scrollTop = loggerContainerEl.scrollHeight;
+
+        imgCache.set(imgName, new WeakRef(newImg));
+        registry.register(newImg, {
+            imgName,
+            size: newImg.size,
+            type: newImg.type,
+        });
+
+        return newImg;
+    };
+};
+
+export const stateObj = {
+    loading: false,
+    drawing: true,
+    collageRendered: false,
+    currentLayout: LAYOUTS[0],
+    selectedImages: new Set(),
+};
diff --git a/2-ui/3-event-details/6-pointer-events/article.md b/2-ui/3-event-details/6-pointer-events/article.md
index 481197653..7c7e24a5c 100644
--- a/2-ui/3-event-details/6-pointer-events/article.md
+++ b/2-ui/3-event-details/6-pointer-events/article.md
@@ -126,7 +126,7 @@ A continuación, se muestra el flujo de acciones del usuario y los eventos corre
 Así que el problema es que el navegador "secuestra" la interacción: `pointercancel` se dispara y no se generan más eventos de `pointermove`.
 
 ```online
-Aquí la demo con eventos de puntero (solamente `arriba/abajo`, `mover` y `cancelar`) registrados en `textarea`:
+Esta es la demo "arrastrar y soltar" con el registro de eventos de puntero (solamente `arriba/abajo`, `mover` y `cancelar`) registrados en `textarea`:
 
 [iframe src="ball" height=240 edit]
 ```
diff --git a/2-ui/4-forms-controls/1-form-elements/article.md b/2-ui/4-forms-controls/1-form-elements/article.md
index 9e62ea5a3..05a1bea70 100644
--- a/2-ui/4-forms-controls/1-form-elements/article.md
+++ b/2-ui/4-forms-controls/1-form-elements/article.md
@@ -244,7 +244,7 @@ Esta sintaxis es opcional. Podemos usar `document.createElement('option')` y asi
 - `defaultSelected` -- si es `true`, entonces se le crea el atributo HTML `selected`,
 - `selected` -- si es `true`, el option se selecciona.
 
-La diferencia entre `defaultSelected` y `selected` es que `defaultSelected` asigna el atributo HTML, el que podemos obtener usando `option.getAttribute('selected')`,  mientras que `selected` hace que el option esté o no seleccionado. 
+La diferencia entre `defaultSelected` y `selected` es que `defaultSelected` define si el atributo HTML (el que obtenemos con `option.getAttribute('selected')`), mientras que `selected` define si el option está seleccionado o no en el DOM.
 
 En la práctica, uno debería usualmente establecer _ambos_ valores en `true` o `false`. O simplemente omitirlos, quedarán con el predeterminado `false`.
 
diff --git a/2-ui/4-forms-controls/3-events-change-input/article.md b/2-ui/4-forms-controls/3-events-change-input/article.md
index d9fd892ba..d0dcffc93 100644
--- a/2-ui/4-forms-controls/3-events-change-input/article.md
+++ b/2-ui/4-forms-controls/3-events-change-input/article.md
@@ -95,7 +95,7 @@ El portapapeles es algo a nivel "global" del SO. Un usuario puede alternar entre
 
 Por ello la mayoría de los navegadores dan acceso al portapapeles únicamente bajo determinadas acciones del usuario, como copiar y pegar.
 
-Está prohibido generar eventos "personalizados" del portapapeles con `dispatchEvent` en todos los navegadores excepto Firefox. Incluso si logramos enviar tal evento, la especificación establece que tal evento "sintético" no debe brindar acceso al portapapeles.
+Está prohibido generar eventos "personalizados" del portapapeles con `dispatchEvent` en todos los navegadores excepto Firefox. Incluso si logramos enviar tal evento, la especificación establece claramente que tal evento "sintético" no debe brindar acceso al portapapeles.
 
 Incluso si alguien decide guardar `event.clipboardData` en un manejador de evento para accederlo luego, esto no funcionará.
 
diff --git a/2-ui/99-ui-misc/02-selection-range/article.md b/2-ui/99-ui-misc/02-selection-range/article.md
index 4a3ebe73e..0d04a6760 100644
--- a/2-ui/99-ui-misc/02-selection-range/article.md
+++ b/2-ui/99-ui-misc/02-selection-range/article.md
@@ -354,7 +354,7 @@ Las principales propiedades de selection son:
 
 ```smart header="Inicio/final, Selection vs. Range"
 
-Hay una diferencia importante entre anchor/focus (ancla/foco) de una selección comparado al inicio/fin de un rango.
+Hay una diferencia importante entre anchor/focus (ancla/foco) de una selección comparado al inicio/fin de un `Range`.
 
 Sabemos que los objetos `Range` siempre tienen el inicio antes que el final.
 
diff --git a/2-ui/99-ui-misc/03-event-loop/article.md b/2-ui/99-ui-misc/03-event-loop/article.md
index 3f35fbf64..db67694ff 100644
--- a/2-ui/99-ui-misc/03-event-loop/article.md
+++ b/2-ui/99-ui-misc/03-event-loop/article.md
@@ -17,7 +17,7 @@ EL algoritmo general del motor:
     - ejecutarlas comenzando por la más antigua.
 2. Dormir hasta que aparezca una tarea, luego volver a 1.
 
-Eso es una formalización de lo que vemos cuando navegamos por una página. El motor JavaScript no hace nada la mayoría del tiempo y solo corre cuando un script/controlador/evento se activa.
+Eso es una formalización de lo que vemos cuando navegamos por una página. La mayor parte del tiempo, el motor de JavaScript no hace nada, solo se ejecuta cuando un script/controlador/evento lo activa.
 
 Ejemplos de tareas:
 
@@ -30,19 +30,19 @@ Las tareas son programadas --&gt; el motor las ejecuta --&gt; <span class="x x-f
 
 Puede ocurrir que una tarea llegue mientras el motor está ocupado, entonces es puesta en cola.
 
-Las tareas forman una cola, también llamada "Cola de macrotarea" (Término de v8):
+Las tareas forman una cola, la llamada "Cola de macrotareas" (terminología de [v8](https://v8.dev/)):
 
 ![](eventLoop.svg)
 
-Por ejemplo, mientras el motor está ocupado ejecutando un `script`, un usuario podría mover su mouse causando `mousemove` o también podría ser `setTimeout`, etc. Todas estas tareas forman una cola como se observa en la imagen arriba.
+Por ejemplo, mientras el motor está ocupado ejecutando un `script`, un usuario podría mover su mouse causando `mousemove`, o también podría ocurrir un `setTimeout`, etc. Todas estas tareas ingresan a la cola como se observa en la imagen arriba.
 
 Las tareas de la cola son ejecutadas según la base "El que primero llega primero se atiende". Cuando el motor del navegador termina con el `script`, se encarga del evento `mousemove`, continúa con `setTimeout`, etc.
 
 Hasta ahora bastante simple, ¿no?
 
 Dos detalles más:
-1. El renderizado nunca ocurre mientras el motor ejecuta una tarea. No importa si la tarea ocupa mucho tiempo. Solo se realizan cambios a DOM una vez que la tarea finaliza.
-2. Si una tarea consume demasiado tiempo, el navegador no puede hacer otras tareas, procesos o eventos por lo que después de un tiempo muestra una alerta "La página no responde" sugiriendo detener la tarea con la página completa. Esto ocurre cuando hay muchos cálculos complejos o un error en la programación que lleva a un bucle infinito.
+1. El renderizado nunca ocurre mientras el motor ejecuta una tarea. No importa si la tarea ocupa mucho tiempo. Solo se realizarán cambios al DOM una vez que la tarea finalice.
+2. Si una tarea consume demasiado tiempo, el navegador no puede ejecutar otras tareas, procesos ni eventos. Cuando esto ocurre, el navegador nos mostrará una alerta "La página no responde" sugiriendo detener la tarea junto con la página completa. Esto puede ocurrir cuando hay muchos cálculos complejos, o por un error en la programación que lleva a un bucle infinito.
 
 Esa fue la teoría. Ahora veamos como podemos aplicar ese conocimiento.
 
@@ -54,7 +54,7 @@ Por ejemplo, el resaltado de sintaxis (usado para colorear ejemplos de código e
 
 Mientras el motor está ocupado con el resaltado de sintaxis, no puede hacer otras cosas relacionadas a DOM, procesar eventos de usuario, etc. Podría incluso provocar que el navegador se "congele" por un momento, lo que es inaceptable.
 
-Podemos evitar problemas dividiendo la tarea en piezas más pequeñas. Resaltar primero 100 líneas, después programar `setTimeout` (con cero delay) para las próximas 100 líneas y así sucesivamente.
+Podemos evitar el problema dividiendo la tarea en piezas más pequeñas. Resaltar primero 100 líneas, después programar `setTimeout` (con cero delay) para las próximas 100 líneas, y así sucesivamente.
 
 Para demostrar este enfoque y en pos de una mayor simplicidad, en lugar de resaltado de texto tomemos una función que cuenta desde `1` hasta `1000000000`.
 
diff --git a/6-data-storage/01-cookie/article.md b/6-data-storage/01-cookie/article.md
index 9b8d3d5d2..c2b771cf6 100644
--- a/6-data-storage/01-cookie/article.md
+++ b/6-data-storage/01-cookie/article.md
@@ -2,7 +2,7 @@
 
 Las cookies son pequeñas cadenas de datos que se almacenan directamente en el navegador. Son parte del protocolo HTTP, definido por la especificación [RFC 6265](https://tools.ietf.org/html/rfc6265).
 
-Las cookies son usualmente establecidos por un servidor web utilizando la cabecera de respuesta HTTP `Set-Cookie`. Entonces, el navegador los agrega automáticamente a (casi) toda solicitud del mismo dominio usando la cabecera HTTP `Cookie`.
+Las cookies generalmente se establecen desde un servidor web utilizando la cabecera de respuesta HTTP `Set-Cookie`. Luego, el navegador los agrega automáticamente a (casi) toda solicitud al mismo dominio usando la cabecera HTTP `Cookie`.
 
 Uno de los casos de uso más difundidos es la autenticación:
 
@@ -12,7 +12,7 @@ Uno de los casos de uso más difundidos es la autenticación:
 
 También podemos acceder a las cookies desde el navegador usando la propiedad `document.cookie`.
 
-Hay muchas cosas intrincadas acerca de las cookies y sus opciones. En este artículo las vamos a ver en detalle.
+Hay muchas complejidades en las cookies y sus atributos. En este artículo las veremos en detalle.
 
 ## Leyendo a document.cookie
 
@@ -33,7 +33,7 @@ alert( document.cookie ); // cookie1=value1; cookie2=value2;...
 
 El valor de `document.cookie` consiste de pares `name=value` delimitados por `; `. Cada uno es una cookie separada.
 
-Para encontrar una cookie particular, podemos separar (split) `document.cookie` por `; ` y encontrar el nombre correcto. Podemos usar tanto una expresión regular como funciones de array para ello.
+Para encontrar una cookie particular, podemos separar `document.cookie` por `; ` y encontrar el nombre correcto. Podemos usar tanto una expresión regular como funciones de array para ello.
 
 Lo dejamos como ejercicio para el lector. Al final del artículo encontrarás funciones de ayuda para manipular cookies.
 
@@ -68,28 +68,19 @@ alert(document.cookie); // ...; my%20name=John%20Smith
 
 ```warn header="Limitaciones"
 Hay algunas limitaciones:
-- El par `name=value`, después de `encodeURIComponent`, no debe exceder 4KB. Así que no podemos almacenar algo enorme en una cookie.
-- La cantidad total de cookies por dominio está limitada a alrededor de 20+, el límite exacto depende del navegador.
+- Solo puedes establecer/modificar una cookie a la vez usando `document.cookie`.
+- El par `name=value`, después del `encodeURIComponent`, no debe exceder 4KB. Así que no podemos almacenar algo enorme en una cookie.
+- La cantidad total de cookies por dominio está limitada a alrededor de más de 20, el límite exacto depende del navegador.
 ```
 
-Las cookies tienen varias opciones, muchas de ellas importantes y deberían ser configuradas.
+Las cookies tienen varios atributos, muchos de ellos importantes y deberían ser configurados.
 
-Las opciones son listadas después de `key=value`, delimitadas por un `;`:
+Las atributos son listados después de `key=value`, delimitadas por un `;`:
 
 ```js run
 document.cookie = "user=John; path=/; expires=Tue, 19 Jan 2038 03:14:07 GMT"
 ```
 
-## path 
-
-- **`path=/mypath`**
-
-La ruta del prefijo path debe ser absoluto. Esto hace la cookie accesible a las páginas bajo esa ruta. La forma predeterminada es la ruta actual.
-
-Si una cookie es establecida con `path=/admin`, será visible en las páginas `/admin` y `/admin/something`, pero no en `/home` o `/adminpage`.
-
-Usualmente, debemos configurarlo en la raíz: `path=/` para hacer la cookie accesible a todas las páginas del sitio web.
-
 ## domain
 
 - **`domain=site.com`**
@@ -102,7 +93,7 @@ Es una restricción de seguridad, para permitirnos almacenar datos sensibles en
 
 De forma predeterminada, una cookie solo es accesible en el dominio que la establece.
 
-Pero por favor toma nota: de forma predeterminada una cookie tampoco es compartida por un subdominio, como `forum.site.com`.
+Pero toma nota: de forma predeterminada, una cookie tampoco es compartida por un subdominio (como `forum.site.com`).
 
 ```js
 // en site.com
@@ -112,9 +103,9 @@ document.cookie = "user=John"
 alert(document.cookie); // no user
 ```
 
-...aunque esto puede cambiarse. Si queremos permitir que un subdominio como `forum.site.com` obtenga una cookie establecida por `site.com`, eso es posible.
+... aunque esto puede cambiarse. Si queremos permitir que un subdominio como `forum.site.com` obtenga una cookie establecida por `site.com`, es posible hacerlo.
 
-Para ello, cuando establecemos una cookie en `site.com`, debemos configurar explícitamente la raíz del dominio en la opción `domain`: `domain=site.com`. Entonces todos los subdominios verán la cookie.
+Para ello, cuando establecemos una cookie en `site.com`, debemos establecer explícitamente la raíz del dominio en el atributo `domain`: `domain=site.com`. Así todos los subdominios verán la cookie.
 
 Por ejemplo:
 
@@ -129,19 +120,31 @@ document.cookie = "user=John; *!*domain=site.com*/!*"
 alert(document.cookie); // tiene la cookie user=John
 ```
 
-Por razones históricas, `domain=.site.com` (con un punto antes de `site.com`) también funciona de la misma forma, permitiendo acceso a la cookie desde subdominios. Esto es una vieja notación y debe ser usada si necesitamos dar soporte a navegadores muy viejos.
+```warn header="Sintaxis heredada"
+Históricamente, `domain=.site.com` (con un punto antes de `site.com`) se usaba para este propósito, permitir el acceso a la cookie desde los subdominios. Actualmente, los puntos al inicio de nombres de dominio se ignoran, pero algunos navegadores podrían rechazar la configuración de cookies que los contengan.
+```
+
+Resumiendo, el atributo `domain` permite que las cookies sean accesibles en los subdominios.
+
+## path 
+
+- **`path=/mypath`**
+
+La ruta URL del prefijo `path` debe ser absoluta. Esto hace que la cookie sea accesible a las páginas bajo esa ruta. De forma predeterminada, es la ruta actual.
+
+Si una cookie se establece con `path=/admin`, será visible en las páginas `/admin` y `/admin/something`, pero no en `/home`, `/adminpage`, o `/`.
 
-Entonces: la opción `domain` permite que las cookies sean accesibles en los subdominios.
+Lo usual es establecer `path` en la raíz: `path=/`, para hacer la cookie accesible a todas las páginas del sitio web. Si este atributo no se establece, el predeterminado es calculado unsando [este método](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#path_default_value).
 
 ## expires, max-age
 
-De forma predeterminada, si una cookie no tiene una de estas opciones, desaparece cuando el navegador se cierra. Tales cookies se denominan "cookies de sesión".
+De forma predeterminada, una cookie desaparece cuando el navegador se cierra. Tales cookies se denominan "cookies de sesión".
 
-Para que las cookies sobrevivan al cierre del navegador, podemos usar las opciones `expires` o `max-age`.
+Para que las cookies sobrevivan al cierre del navegador, podemos establecer uno de estos atrubutos: `expires` o `max-age`.
 
 - **`expires=Tue, 19 Jan 2038 03:14:07 GMT`**
 
-La fecha de expiración define el momento en que el navegador la borra automáticamente.
+La fecha de expiración define el momento en que el navegador la borrará automáticamente (según la zona horaria del navegador).
 
 La fecha debe estar exactamente en ese formato, en el huso horario GMT. Podemos obtenerlo con `date.toUTCString`. Por ejemplo, podemos configurar que la cookie expire en un día:
 
@@ -158,7 +161,7 @@ Si establecemos `expires` en una fecha en el pasado, la cookie es eliminada.
 
 `max-age` es una alternativa a `expires`, y especifica la expiración de la cookie en segundos desde el momento actual.
 
-Si la configuramos a cero o un valor negativo, la cookie es eliminada:
+Si la configuramos a cero, o a un valor negativo, la cookie se elimina:
 
 ```js
 // la cookie morirá en +1 hora a partir de ahora
@@ -178,7 +181,7 @@ La cookie debe ser transferida solamente a través de HTTPS.
 
 Esto es, las cookies están basadas en el dominio, no distinguen entre protocolos.
 
-Con la opción `secure`, si una cookie se establece por `https://site.com`, entonces no aparecerá cuando el mismo sitio es accedido por HTTP, como `http://site.com`. Entonces, si una cookie tiene información sensible que nunca debe ser enviada sobre HTTP sin encriptar, debe configurarse `secure`.
+Con el atributo `secure`, si una cookie se establece para `https://site.com`, entonces no aparecerá cuando el mismo sitio sea accedido por HTTP, como `http://site.com`. Entonces, si una cookie tiene información sensible que nunca debe ser enviada sobre HTTP sin encriptar, debe configurarse `secure`.
 
 ```js
 // asumiendo que estamos en https:// ahora
@@ -188,7 +191,7 @@ document.cookie = "user=John; secure";
 
 ## samesite
 
-Este es otro atributo de seguridad. `samesite` sirve para proteger contra los ataques llamados XSRF (falsificación de solicitud entre sitios, cross-site request forgery).
+Este es otro atributo de seguridad. `samesite` está diseñado para protección contra los ataques XSRF (cross-site request forgery, falsificación de solicitud entre sitios).
 
 Para entender cómo funciona y su utilidad, veamos primero los ataques XSRF.
 
@@ -196,7 +199,7 @@ Para entender cómo funciona y su utilidad, veamos primero los ataques XSRF.
 
 Imagina que tienes una sesión en el sitio `bank.com`. Esto es: tienes una cookie de autenticación para ese sitio. Tu navegador lo envía a `bank.com` en cada solicitud, así aquel te reconoce y ejecuta todas las operaciones financieras sensibles.
 
-Ahora, mientras navegas la red en otra ventana, accidentalmente entras en otro sitio `evil.com`. Este sitio tiene código JavaScript que envía un formulario `<form action="https://bank.com/pay">` a `bank.com` con los campos que inician una transacción a la cuenta el hacker.
+Ahora, mientras navegas la red en otra ventana, accidentalmente entras en otro sitio `evil.com`. Este sitio tiene código JavaScript que envía un formulario `<form action="https://bank.com/pay">` a `bank.com` con los campos que inician una transacción hacia la cuenta del hacker.
 
 El navegador envía cookies cada vez que visitas el sitio `bank.com`, incluso si el form fue enviado desde `evil.com`. Entonces el banco te reconoce y realmente ejecuta el pago.
 
@@ -208,29 +211,29 @@ Los bancos reales están protegidos contra esto por supuesto. Todos los formular
 
 Tal protección toma tiempo para implementarla. Necesitamos asegurarnos de que cada form tiene dicho campo token, y debemos verificar todas las solicitudes.
 
-### Opción de cookie samesite
+### Uso del atributo samesite
 
-La opción `samesite` brinda otra forma de proteger tales ataques, que (en teoría) no requiere el "token de protección XSRF".
+El atributo `samesite` brinda otra forma de protegerse de tales ataques, que (en teoría) no requiere el "token de protección XSRF".
 
 Tiene dos valores posibles:
 
-- **`samesite=strict` (lo mismo que `samesite` sin valor)**
+- **`samesite=strict`**
 
 Una cookie con `samesite=strict` nunca es enviada si el usuario viene desde fuera del mismo sitio.
 
 En otras palabras, si el usuario sigue un enlace desde su correo, envía un form desde `evil.com`, o hace cualquier operación originada desde otro dominio, la cookie no será enviada.
 
-Si las cookies de autenticación tienen la opción `samesite`, un ataque XSRF no tiene posibilidad de éxito porque el envío de `evil.com` llega sin cookies. Así `bank.com` no reconoce el usuario y no procederá con el pago.
+Cuando las cookies de autenticación tienen el atributo `samesite=strict`, un ataque XSRF no tiene posibilidad de éxito, porque el envío de `evil.com` llega sin cookies. Así `bank.com` no reconoce el usuario y no procederá con el pago.
 
-La protección es muy confiable. Solo las operaciones que vienen de `bank.com` enviarán la cookie `samesite`, por ejemplo un form desde otra página de `bank.com`.
+Esta protección es muy confiable. Solo las operaciones que provienen de `bank.com` enviarán la cookie `samesite=strict`, por ejemplo, el envío de un form desde otra página en `bank.com`.
 
 Aunque hay un pequeño inconveniente.
 
 Cuando el usuario sigue un enlace legítimo a `bank.com`, por ejemplo desde sus propio correo, será sorprendido con que `bank.com` no lo reconoce. Efectivamente, las cookies `samesite=strict` no son enviadas en ese caso.
 
-Podemos sortear esto usando dos cookies: una para el "reconocimiento general", con el solo propósito de decir: "Hola, John", y la otra para operaciones de datos con `samesite=strict`. Entonces, la persona que venga desde fuera del sitio llega a la página de bienvenida, pero los pagos serán iniciados desde dentro del sitio web del banco, entonces la segunda cookie sí será enviada.
+Podemos sortear esto usando dos cookies: una para el "reconocimiento general", con el solo propósito de decir: "Hola, John", y la otra para operaciones de datos con `samesite=strict`. Entonces, la persona que venga desde fuera del sitio llega a la página de bienvenida, pero los pagos serían iniciados desde dentro del sitio web del banco, entonces la segunda cookie sí será enviada.
 
-- **`samesite=lax`**
+- **`samesite=lax` (es lo mismo que `samesite` sin un valor)**
 
 Un enfoque más laxo que también protege de ataques XSRF y no afecta la experiencia de usuario.
 
@@ -239,37 +242,37 @@ El modo `lax`, como `strict`, prohíbe al navegador enviar cookies cuando viene
 Una cookie `samesite=lax` es enviada si se cumplen dos condiciones:
 1. El método HTTP es seguro (por ejemplo GET, pero no POST).
 
-    La lista completa de métodos seguros HTTP está en la especificación [RFC7231](https://tools.ietf.org/html/rfc7231). Básicamente son métodos usados para leer, pero no escribir datos. Los que no ejecutan ninguna operación de alteración de datos. Seguir un enlace es siempre GET, el método seguro.
+    La lista completa de métodos seguros HTTP está en la especificación [RFC7231](https://tools.ietf.org/html/rfc7231#section-4.2.1). Son métodos que deben ser usados para leer, pero no escribir datos. No debem ejecutar ninguna operación de alteración de datos. Seguir un enlace es siempre GET, el método seguro.
 
 2. La operación ejecuta una navegación del más alto nivel (cambia la URL en la barra de dirección del navegador).
 
-    Esto es usualmente verdad, pero si la navegación en ejecutada dentro de un `<iframe>`, entonces no es de alto nivel. Tampoco encajan aquí los métodos JavaScript para solicitudes de red porque no ejecutan ninguna navegación.
+    Generalmente esto es verdad, pero si la navegación es ejecutada dentro de un `<iframe>`, entonces no es de alto nivel. Además, los métodos JavaScript para solicitudes de red no ejecutan ninguna navegación.
 
-Entonces, lo que hace `samesite=lax` es básicamente permitir la operación más común "ir a URL" para obtener cookies. Por ejemplo, abrir un sitio desde la agenda satisface estas condiciones.
+Entonces, lo que hace `samesite=lax` es permitir la operación más común "ir a URL" para obtener cookies. Por ejemplo, abrir un sitio desde el link en una agenda sí satisface estas condiciones.
 
 Pero cualquier cosa más complicada, como solicitudes de red desde otro sitio, o un "form submit", pierde las cookies.
 
 Si esto es adecuado para ti, entonces agregar `samesite=lax` probablemente no dañe la experiencia de usuario y agrega protección.
 
-Por sobre todo, `samesite` es una excelente opción.
+Por sobre todo, `samesite` es un atributo excelente.
 
 Tiene una importante debilidad:
 
-- `samesite` es ignorado (no soportado) por navegadores viejos, de alrededor de 2017.
+- `samesite` es ignorado (no soportado) por navegadores viejos, de hasta alrededor de 2017.
 
 **Así que si solo confiamos en `samesite` para brindar protección, habrá navegadores que serán vulnerables.**
 
-Pero con seguridad podemos usar `samesite`, junto con otras medidas de protección como los tokens xsrf, para agregar una capa adicional de defensa. En el futuro probablemente podamos descartar la necesidad de tokens xsrf.
+Pero podemos usar `samesite` junto con otras medidas de protección, como los tokens xsrf, para agregar una capa adicional de defensa. En el futuro, cuando los viejos navegadores mueran, probablemente podamos descartar la necesidad de tokens xsrf.
 
 ## httpOnly
 
-Esta opción no tiene nada que ver con JavaScript, pero tenemos que mencionarla para completar la guía.
+Est atributo no tiene nada que ver con JavaScript, pero debemos mencionarlo para completar la guía.
 
-El servidor web usa la cabecera `Set-Cookie` para establecer la cookie. También puede configurar la opción `httpOnly`.
+El servidor web usa la cabecera `Set-Cookie` para establecer la cookie. También puede establecer el atributo `httpOnly`.
 
-Esta opción impide a JavaScript el acceso a la cookie. No podemos ver ni manipular tal cookie usando `document.cookie`.
+Este atributo impide a JavaScript todo acceso a la cookie. No podemos ver ni manipular tal cookie usando `document.cookie`.
 
-Esto es usado como medida de precaución, para proteger de ciertos ataques donde el hacker inyecta su propio código en una página y espera que el usuario visite esa página. Esto no debería ser posible en absoluto, los hackers bo deberían poder insertar su código en nuestro sitio, pero puede haber bugs que les permite hacerlo.
+Esto es usado como medida de precaución, para proteger de ciertos ataques donde el hacker inyecta su propio código JavaScript en una página y espera que el usuario visite esa página. Esto no debería ser posible en absoluto, los hackers no deberían poder insertar su código en nuestro sitio, pero puede haber bugs que les permitan hacerlo.
 
 
 Normalmente, si eso sucede y el usuario visita una página web con el código JavaScript del hacker, entonces ese código se ejecuta y gana acceso a `document.cookie` con las cookies del usuario conteniendo información de autenticación. Eso es malo.
@@ -303,30 +306,30 @@ Aquí `new RegExp` se genera dinámicamente para coincidir `; name=<value>`.
 
 Nota que el valor de una cookie está codificado, entonces `getCookie` usa una función integrada `decodeURIComponent` para decodificarla.
 
-### setCookie(name, value, options)
+### setCookie(name, value, attributes)
 
 Establece el nombre de la cookie `name` al valor dado `value`, con la ruta por defecto `path=/`, y puede ser modificada para agregar otros valores predeterminados:
 
 ```js run
-function setCookie(name, value, options = {}) {
+function setCookie(name, value, attributes = {}) {
 
-  options = {
+  attributes = {
     path: '/',
     // agregar otros valores predeterminados si es necesario
-    ...options
+    ...attributes
   };
 
-  if (options.expires instanceof Date) {
-    options.expires = options.expires.toUTCString();
+  if (attributes.expires instanceof Date) {
+    attributes.expires = attributes.expires.toUTCString();
   }
 
   let updatedCookie = encodeURIComponent(name) + "=" + encodeURIComponent(value);
 
-  for (let optionKey in options) {
-    updatedCookie += "; " + optionKey;
-    let optionValue = options[optionKey];
-    if (optionValue !== true) {
-      updatedCookie += "=" + optionValue;
+  for (let attributeKey in attributes) {
+    updatedCookie += "; " + attributeKey;
+    let attributeValue = attributes[attributeKey];
+    if (attributeValue !== true) {
+      updatedCookie += "=" + attributeValue;
     }
   }
 
@@ -394,13 +397,13 @@ Si un script configura una cookie, no importa de dónde viene el script: la cook
 
 Este tópico no está relacionado a JavaScript en absoluto, solo es algo para tener en mente cuando configuramos cookies.
 
-Hay una legislación en Europa llamada GDPR que es un conjunto de reglas que fuerza a los sitios web a respetar la privacidad del usuario. Una de estas reglas es requerir un permiso explícito del usuario para el uso de cookies de seguimiento.
+Hay una legislación en Europa llamada GDPR. Es un conjunto de reglas que fuerza a los sitios web a respetar la privacidad del usuario. Una de estas reglas es requerir el permiso explícito del usuario para el uso de cookies de seguimiento.
 
 Nota que esto solo se refiere a cookies de seguimiento, identificación y autorización.
 
 Así que si queremos configurar una cookie que solo guarda alguna información pero no hace seguimiento ni identificación del usuario, somos libres de hacerlo.
 
-Pero si vamos a configurar una  cookie con una sesión de autenticación o un id de seguimiento, el usuario debe dar su permiso.
+Pero si vamos a configurar una cookie con una sesión de autenticación o un id de seguimiento, el usuario debe dar su permiso.
 
 Los sitios web generalmente tienen dos variantes para cumplir con el GDPR. Debes de haberlas visto en la web:
 
@@ -421,15 +424,15 @@ El GDPR no trata solo de cookies, también es acerca de otros problemas relacion
 `document.cookie` brinda acceso a las cookies.
 - la operación de escritura modifica solo cookies mencionadas en ella.
 - nombre y valor deben estar codificados.
-- Una cookie no debe exceder los 4KB, y están limitadas a unas 20+ cookies por sitio (depende del navegador).
+- Una cookie no debe exceder los 4 KB. El número de cookies está limitado a alrededor de más de 20 por sitio (depende del navegador).
 
-Opciones de Cookie:
+Atributos de Cookie:
 - `path=/`, por defecto la ruta actual, hace la cookie visible solo bajo esa ruta.
 - `domain=site.com`, por defecto una cookie es visible solo en el dominio actual. Si el domino se establece explícitamente, la cookie se hace visible a los subdominios.
-- `expires` o `max-age` configuran el tiempo de expiración de la cookie. Sin ellas la cookie muere cuando el navegador es cerrado.
+- `expires` o `max-age` configuran el tiempo de expiración de la cookie. Sin ellas la cookie muere cuando el navegador se cierra.
 - `secure` hace la cookie solo para HTTPS.
 - `samesite` prohíbe al navegador enviar la cookie a solicitudes que vengan desde fuera del sitio. Esto ayuda a prevenir ataques XSRF.
 
 Adicionalmente:
-- Las cookies de terceros pueden estar prohibidas por el navegador, por ejemplo Safari lo hace por defecto.
+- El navegador puede prohibir las cookies de terceros. Por ejemplo, Safari lo hace por defecto.
 - Cuando se configuran cookies de seguimiento para ciudadanos de la UE, la regulación GDPR requiere la autorización del usuario.
diff --git a/6-data-storage/03-indexeddb/article.md b/6-data-storage/03-indexeddb/article.md
index ca60f3d7e..f4a46a863 100644
--- a/6-data-storage/03-indexeddb/article.md
+++ b/6-data-storage/03-indexeddb/article.md
@@ -16,7 +16,7 @@ Toda esta potencia es normalmente excesiva para las aplicaciones cliente-servido
 
 La interfaz nativa de IndexedDB, descrita en la <https://www.w3.org/TR/IndexedDB>, está basada en eventos.
 
-También podemos usar `async/await` con la ayuda de un contenedor basado en promesas como idb <https://github.com/jakearchibald/idb>. Aunque esto es muy conveniente, hay que tener en cuenta que el contenedor no es perfecto y no puede reemplazar a los eventos en todos los casos. Así que comenzaremos con eventos y, cuando hayamos avanzado en el entendimiento de IndexedDB, usaremos el contenedor.
+También podemos usar `async/await` con la ayuda de un contenedor basado en promesas, como idb <https://github.com/jakearchibald/idb>. Sin embargo, hay que tener en cuenta que el contenedor no es perfecto y no puede reemplazar a los eventos en todos los casos. Así que comenzaremos con eventos y, cuando hayamos avanzado en el entendimiento de IndexedDB, usaremos el contenedor.
 
 ```smart header="¿Dónde están los datos?"
 Técnicamente, los datos son almacenados bajo el directorio raíz del usuario junto con la configuración personal del navegador, extensiones, etc.
diff --git a/7-animation/2-css-animations/article.md b/7-animation/2-css-animations/article.md
index 93863ab16..e63907875 100644
--- a/7-animation/2-css-animations/article.md
+++ b/7-animation/2-css-animations/article.md
@@ -462,7 +462,7 @@ La propiedad `opacity` tampoco dispara "Layout" (también se salta "Paint" en Ge
 
 Aparear `transform` con `opacity` puede usualmente resolver la mayoría de nuestras necesidades brindando animaciones vistosas y fluidas.
 
-Aquí por ejemplo, clic en el elemento `#boat` le agrega la clase con `transform: translateX(300)` y `opacity: 0`, haciendo que se mueva `300px` a la derecha y desaparezca:
+Aquí, por ejemplo, un clic en el elemento `#boat` le agrega la clase con `transform: translateX(300)` y `opacity: 0`, haciendo que se mueva `300px` a la derecha y desaparezca:
 
 ```html run height=260 autorun no-beautify
 <img src="https://js.cx/clipart/boat.png" id="boat">
diff --git a/9-regular-expressions/11-regexp-groups/article.md b/9-regular-expressions/11-regexp-groups/article.md
index 30e166086..c25e36b61 100644
--- a/9-regular-expressions/11-regexp-groups/article.md
+++ b/9-regular-expressions/11-regexp-groups/article.md
@@ -209,9 +209,9 @@ alert(results[0]); // <h1>,h1 (1er etiqueta)
 alert(results[1]); // <h2>,h2 (2da etiqueta)
 ```
 
-Como podemos ver, la primera diferencia es muy importante, como se demuestra en la línea `(*)`. No podemos obtener la coincidencia como `results[0]`, porque ese objeto no es pseudo array. Lo podemos convertir en un `Array` real utilizando `Array.from`. Hay más detalles sobre pseudo arrays e iterables en el artículo. <info:iterable>.
+Como se demuestra en la línea `(*)`, la primera diferencia es muy importante. No podemos obtener la coincidencia como `results[0]`, porque ese objeto es un pseudo array. Lo podemos convertir en un `Array` real utilizando `Array.from`. Hay más detalles sobre pseudo arrays e iterables en el artículo. <info:iterable>.
 
-No se necesita `Array.from` si estamos iterando sobre los resultados:
+No necesitamos `Array.from` si estamos iterando sobre los resultados:
 
 ```js run
 let results = '<h1> <h2>'.matchAll(/<(.*?)>/gi);
diff --git a/BACKERS.md b/BACKERS.md
new file mode 100644
index 000000000..36b1532bc
--- /dev/null
+++ b/BACKERS.md
@@ -0,0 +1,6 @@
+
+# Sponsors and Supporters
+
+## Supporters
+
+- Ilya Zelenko
diff --git a/LICENSE.md b/LICENSE.md
index acfce9082..cbada5307 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -7,7 +7,7 @@ As of now, we license the tutorial to almost everyone for free under the terms o
 
 ## License (Short)
 
-The license is basically [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode), revocable and exclusive.
+The license is based on [CC-BY-NC](https://creativecommons.org/licenses/by-nc/4.0/legalcode).
 
 It gives the right to:
 - **Share** – copy and redistribute the tutorial in any medium or material.
@@ -15,68 +15,62 @@ It gives the right to:
 
 Under the following terms:
 
-- **Attribution** — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
+- **Attribution** — You must give appropriate credit. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
 - **NonCommercial** — You may not use the material for commercial purposes.
 
 ## License (Legal)
 
-By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this license ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.
+By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this license ("License"). To the extent this License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.
 
 ### Section 1 – Definitions.
 
-a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
+a. __Adapted Material__ means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
 
-b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.
+b. __Adapter's License__ means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this License.
 
-c. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
+c. __Copyright and Similar Rights__ means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
 
 d. __Effective Technological Measures__ means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
 
 e. __Exceptions and Limitations__ means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
 
-f. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this Public License.
+f. __Licensed Material__ means the artistic or literary work, database, or other material to which the Licensor applied this License.
 
-g. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
+g. __Licensed Rights__ means the rights granted to You subject to the terms and conditions of this License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
 
-h. __Licensor__ means the individual(s) or entity(ies) granting rights under this Public License.
+h. __Licensor__ means the individual(s) or entity(ies) granting rights under this License.
 
-i. __NonCommercial__ means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange.
+i. __NonCommercial__ means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange.
 
 j. __Share__ means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.
 
 k. __Sui Generis Database Rights__ means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
 
-l. __You__ means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.
+l. __You__ means the individual or entity exercising the Licensed Rights under this License. Your has a corresponding meaning.
 
 ### Section 2 – Scope.
 
 a. ___License grant.___
 
-   1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
+   1. Subject to the terms and conditions of this License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive license to exercise the Licensed Rights in the Licensed Material to:
 
        A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and
 
        B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only.
 
-   2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
+   2. __Exceptions and Limitations.__ For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this License does not apply, and You do not need to comply with its terms and conditions.
 
-   3. __Term.__ The term of this Public License is specified in Section 6(a).
+   3. __Term.__ The term of this License is specified in Section 6(a).
 
-   4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
+   4. __Media and formats; technical modifications allowed.__ The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
 
-   5. __Downstream recipients.__
-
-        A. __Offer from the Licensor – Licensed Material.__ Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
-
-        B. __No downstream restrictions.__ You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.
-
-   6. __No endorsement.__ Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).
+   5. __No endorsement.__ Nothing in this License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3.
 
 b. ___Other rights.___
 
-   1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.
+   1. Moral rights, such as the right of integrity, are not licensed under this License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.
 
-   2. Patent and trademark rights are not licensed under this Public License.
+   2. Patent and trademark rights are not licensed under this License.
 
    3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes.
 
@@ -84,31 +78,15 @@ b. ___Other rights.___
 
 Your exercise of the Licensed Rights is expressly made subject to the following conditions.
 
-a. ___Attribution.___
-
-   1. If You Share the Licensed Material (including in modified form), You must:
-
-       A. retain the following if it is supplied by the Licensor with the Licensed Material:
-
-         i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
+1. If You Share the Licensed Material (including in modified form), You must attribute the Licensor by adding:
 
-         ii. a copyright notice;
+   i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
 
-         iii. a notice that refers to this Public License;
+   ii. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
 
-         iv. a notice that refers to the disclaimer of warranties;
+2. You may satisfy the conditions in Section 3(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.
 
-         v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
-
-       B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
-
-       C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
-
-   2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.
-
-   3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.
-
-   4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License.
+3. If requested by the Licensor, You must remove any of the information required by Section 3(1) to the extent reasonably practicable.
 
 ### Section 4 – Sui Generis Database Rights.
 
@@ -118,21 +96,21 @@ a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract,
 
 b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and
 
-c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.
+c. You must comply with the conditions in Section 3 if You Share all or a substantial portion of the contents of the database.
 
-For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.
+For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this License where the Licensed Rights include other Copyright and Similar Rights.
 
 ### Section 5 – Disclaimer of Warranties and Limitation of Liability.
 
 a. __Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.__
 
-b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__
+b. __To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.__
 
 c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
 
 ### Section 6 – Term and Termination.
 
-a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.
+a. This License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this License, then Your rights under this License terminate automatically.
 
 b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
 
@@ -140,24 +118,26 @@ b. Where Your right to use the Licensed Material has terminated under Section 6(
 
    2. upon express reinstatement by the Licensor.
 
-   For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.
+   For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this License.
+
+c. Notwithstanding the above, the Licensor reserves the right to terminate this License with respect to You if the Licensor expressly notifies You of the termination.
 
-c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
+d. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time.
 
-d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
+e. Sections 1, 5, 6, 7, and 8 survive termination of this License.
 
 ### Section 7 – Other Terms and Conditions.
 
 a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.
 
-b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.
+b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this License.
 
 ### Section 8 – Interpretation.
 
-a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.
+a. For the avoidance of doubt, this License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this License.
 
-b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.
+b. To the extent possible, if any provision of this License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this License without affecting the enforceability of the remaining terms and conditions.
 
-c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
+c. No term or condition of this License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
 
-d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.
+d. Nothing in this License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.
