diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1269488
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+data
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..8b906ae
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,184 @@
+# napi.qvd.tech — Retroalimentación a Estudiantes
+
+## ✅ Estado: MVP FUNCIONAL (2026-02-22)
+
+---
+
+## Contexto
+
+Proyecto minimalista para proporcionar retroalimentación personalizada a los estudiantes de DDAW2, cerrando el bucle profesor → alumno.
+
+El profesor (Fénix) mantiene ficheros `notas.md` por alumno con:
+- Tabla resumen de todas las prácticas (nota + estado)
+- Feedback detallado por práctica
+- Próximos pasos concretos
+
+Los alumnos acceden desde cualquier dispositivo con su navegador, sin instalar nada.
+
+---
+
+## Arquitectura Final
+
+```
+aldebaran (local) zzz (qu3v3d0.tech)
+───────────────── ──────────────────
+~/napi-data/ sshfs /var/www/napi/data/
+ ├── anas/notas.md ←──────────→ ├── anas/notas.md
+ ├── pablo/notas.md ├── pablo/notas.md
+ ├── miguel/notas.md ├── miguel/notas.md
+ └── .../ (19 alumnos) └── .../ (19 alumnos)
+
+ /var/www/napi/
+ ├── viewer.html (app completa)
+ └── marked.min.js (renderer local)
+
+Nginx + libnginx-mod-http-auth-pam
+ → auth con credenciales SFTP del alumno
+ → $remote_user → sirve /var/www/napi/data/$remote_user/notas.md
+ → viewer.html renderiza el .md en el navegador (marked.js local)
+```
+
+### Stack
+
+| Componente | Tecnología | Dónde |
+|:-----------|:-----------|:------|
+| **Datos** | Ficheros `notas.md` (Markdown) | `zzz:/var/www/napi/data/` |
+| **Transporte** | sshfs mount persistente | aldebaran → zzz |
+| **Servidor web** | Nginx | zzz |
+| **Autenticación** | `libnginx-mod-http-auth-pam` | zzz |
+| **Renderer** | `marked.min.js` (local, sin CDN) + `viewer.html` | zzz |
+| **Notificaciones** (watcher nginx) | Python + slixmpp → XMPP | zzz |
+
+**Sin backend. Sin Python para servir. Sin JSON. Sin Syncthing.**
+
+---
+
+## URL de Acceso
+
+```
+https://notas.qu3v3d0.tech
+```
+
+Una sola URL para todos los alumnos. Nginx usa `$remote_user` tras auth_pam para servir el `.md` correcto.
+
+- Alumno ingresa sus credenciales SFTP (mismas que FileZilla)
+- Ve únicamente sus propias notas
+- Refresco del navegador = actualización inmediata
+
+---
+
+## Ficheros Clave en zzz
+
+| Ruta | Descripción |
+|:-----|:------------|
+| `/var/www/napi/data/$alumno/notas.md` | Fuente de datos por alumno |
+| `/var/www/napi/viewer.html` | App completa (fetch + marked.js) |
+| `/var/www/napi/marked.min.js` | Renderer Markdown local |
+| `/etc/nginx/sites-enabled/napi` | Config Nginx del servicio |
+
+`www-data` está en grupo `shadow` (necesario para auth_pam).
+
+---
+
+## Ficheros Clave en aldebaran
+
+| Ruta | Descripción |
+|:-----|:------------|
+| `~/napi-data/` | Mount sshfs → `/var/www/napi/data/` en zzz |
+| `~/.config/systemd/user/home-fenix-napi\x2ddata.mount` | Unit systemd persistente |
+| `~/napi-data/_plantilla/notas.md` | Plantilla para alumnos nuevos |
+| `~/napi-data/README.md` | Documentación del proyecto |
+
+---
+
+## Workflow Emacs (edición)
+
+```
+1. C-x C-f ~/napi-data/pablo/notas.md
+2. Editar → C-x C-s
+3. Alumno refresca navegador → cambios visibles al instante
+```
+
+El sshfs hace que guardar en aldebaran sea equivalente a escribir directamente en zzz.
+
+---
+
+## Formato notas.md
+
+```markdown
+# Notas — NombreAlumno
+
+> 🏫 Módulo: DDAW2
+> 📅 Última actualización: FECHA
+
+## 📊 Resumen
+| Práctica | Título | Nota | Estado |
+| P2.3 | Nginx via SFTP | 7/10 | ✅ |
+...
+
+## P2.7 — Multi-sitio Web con Nginx
+**Nota: 9/10**
+[feedback personalizado]
+
+### Criterios
+| Criterio | Puntos | Estado |
+...
+```
+
+Ver `_plantilla/notas.md` y cualquier alumno como referencia.
+
+---
+
+## Alumnos Activos (19) — DDAW2
+
+```
+anas, carlos, carlosv, daniel, danieln, erick, evelin, gianfranco,
+giorgio, joel, jorge, josue, juanan, juanjesus, kasandra, marius,
+miguel, pablo, patrick
+```
+
+Credenciales SFTP en `~/EducaMadrid/DDAW2/PRACTICA2.4-despliegue-web-HTTP-y-HTTPS/README.md`.
+
+---
+
+## SSH / Conexión a zzz
+
+```bash
+ssh fenix@qu3v3d0.tech # clave sin -i
+```
+
+`fenix` tiene sudo en zzz. Alumnos: grupo `sftpusers`, chroot `/home/$user`.
+
+---
+
+## Añadir Alumno Nuevo
+
+```bash
+# 1. En zzz: crear usuario SFTP (ver README de P2.4 para el script completo)
+sudo useradd -m -d /home/$USER -s /usr/sbin/nologin -G sftpusers,www-data $USER
+
+# 2. En aldebaran: crear carpeta de notas
+mkdir ~/napi-data/$USER
+cp ~/napi-data/_plantilla/notas.md ~/napi-data/$USER/notas.md
+# Editar con Emacs y personalizar
+```
+
+---
+
+## Prácticas Documentadas
+
+| Práctica | Directorio local | Descripción |
+|:---------|:-----------------|:------------|
+| P2.3 | `~/EducaMadrid/DDAW2/PRACTICA2.3-despliegue-nginx-via-sftp/` | Nginx config via SFTP + watcher inotify + XMPP |
+| P2.4 | `~/EducaMadrid/DDAW2/PRACTICA2.4-despliegue-web-HTTP-y-HTTPS/` | HTTP + HTTPS con cert wildcard autofirmado |
+| P2.5 | `~/EducaMadrid/DDAW2/PRACTICA2.5-despliegue-web-bloquear-CDN-JS+servir-MD/` | CSP + bloqueo CDN + marked.js local |
+| P2.6 | `~/EducaMadrid/DDAW2/PRACTICA2.6-Hextris-compresion-cache-y-mejora-de-rendimiento/` | Hextris + gzip + caché |
+| P2.7 | `~/EducaMadrid/DDAW2/PRACTICA2.7-MULTI-SITIO-WEB-NGINX@zzz/` | Multi-sitio: Hextris + App propia + CSP + cabeceras |
+
+---
+
+## Pendiente
+
+- [ ] Rellenar notas de pablo (P2.3 → P2.6 pendientes de detallar)
+- [ ] Considerar CSS más elaborado para viewer.html (opcional)
+- [ ] Renovar certificado SSL wildcard cuando expire (generado 2026-02-04, válido 365 días)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..73e2d0e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,425 @@
+# napi-data — Notas Personalizadas para Estudiantes
+
+> Sistema minimalista para servir retroalimentación personalizada a cada alumno,
+> directamente desde ficheros Markdown editados con Emacs.
+
+**Estado:** ✅ Producción — `https://notas.qu3v3d0.tech` (2026-02-22)
+
+---
+
+## ¿Qué hace esto?
+
+Cada alumno entra en `https://notas.TU_DOMINIO` con sus credenciales SFTP y ve
+**únicamente sus propias notas** en formato HTML renderizado. El profesor edita
+un fichero `.md` desde Emacs y el alumno lo ve al refrescar el navegador.
+
+**Sin backend. Sin base de datos. Sin framework. Sin CDN.**
+
+---
+
+## Arquitectura
+
+```
+PROFESOR (aldebaran / máquina local)
+────────────────────────────────────
+~/napi-data/ ← sshfs mount
+ ├── _plantilla/notas.md
+ ├── alumno01/notas.md ──┐
+ ├── alumno02/notas.md ──┤ escribe con Emacs
+ └── alumnoN/notas.md ──┘ C-x C-s → visible al instante
+
+ │ sshfs (SSH port 22)
+ ▼
+
+SERVIDOR (zzz / Debian VPS)
+────────────────────────────
+/var/www/api/
+ ├── viewer.html ← app completa (~40 líneas)
+ ├── marked.min.js ← renderer Markdown local (sin CDN)
+ └── data/
+ ├── alumno01/notas.md
+ ├── alumno02/notas.md
+ └── alumnoN/notas.md
+
+Nginx + libnginx-mod-http-auth-pam
+ ↓ auth con credenciales SFTP del alumno
+ ↓ $remote_user = "alumno01"
+ ↓ sirve data/alumno01/notas.md
+ ↓ viewer.html lo renderiza en el navegador
+
+ALUMNO (cualquier dispositivo)
+───────────────────────────────
+https://notas.TU_DOMINIO
+ → login con sus credenciales SFTP
+ → ve sus notas en HTML
+ → refresca → cambios inmediatos
+```
+
+---
+
+## Gestión de registros DNS
+
+- Se requiere un https://TU_DOMINIO ad-hoc
+
+- Por simplicidad, necesitas apuntar TODOS los subodminios a la dirección IP del servidor (usa 'wildcard' - '*')
+
+## Requisitos del servidor (Debian)
+
+- Debian 11/12/...
+- Nginx
+- `libnginx-mod-http-auth-pam`
+- `libpam-runtime` (incluido por defecto)
+- Certificado SSL (Let's Encrypt o autofirmado)
+- Usuarios SFTP ya configurados en el sistema (grupo `sftpusers`) usando 'chroot' , partiendo de que cada estudiante tiene su 'usuario' del sistema.
+- SSH accesible desde la máquina del profesor (para sshfs)
+
+---
+
+## Despliegue desde cero en un Debian nuevo
+
+### 1. Instalar dependencias
+
+```bash
+sudo apt update
+sudo apt install -y nginx libnginx-mod-http-auth-pam
+```
+
+### 2. Crear estructura de directorios en el servidor
+
+```bash
+sudo mkdir -p /var/www/api/data
+sudo chown -R www-data:www-data /var/www/api
+sudo chmod 755 /var/www/api
+sudo chmod 755 /var/www/api/data
+```
+
+### 3. Desplegar viewer.html y marked.min.js
+
+```bash
+# Copiar viewer.html al servidor (ver sección "Ficheros de la app" más abajo)
+sudo cp viewer.html /var/www/api/viewer.html
+sudo chown www-data:www-data /var/www/api/viewer.html
+
+# Descargar marked.min.js (o copiar desde backup)
+# https://cdn.jsdelivr.net/npm/marked/marked.min.js
+sudo wget -O /var/www/api/marked.min.js \
+ https://cdn.jsdelivr.net/npm/marked/marked.min.js
+sudo chown www-data:www-data /var/www/api/marked.min.js
+```
+
+> ⚠️ Una vez descargado `marked.min.js`, la app funciona **sin conexión a CDNs**
+> — es el punto del diseño. No actualices el fichero sin probarlo primero.
+
+### 4. Añadir www-data al grupo shadow (para auth_pam)
+
+```bash
+sudo usermod -aG shadow www-data
+# Reiniciar nginx para que tome el cambio de grupo
+sudo systemctl restart nginx
+```
+
+### 5. Configurar Nginx
+
+Crear `/etc/nginx/sites-available/napi`:
+
+```nginx
+server {
+ listen 443 ssl;
+ server_name notas.TU_DOMINIO;
+
+ # --- SSL ---
+ ssl_certificate /etc/ssl/certs/TU_DOMINIO.crt;
+ ssl_certificate_key /etc/ssl/private/TU_DOMINIO.key;
+ ssl_protocols TLSv1.2 TLSv1.3;
+ ssl_ciphers HIGH:!aNULL:!MD5;
+
+ root /var/www/api;
+ index viewer.html;
+
+ # --- Autenticación PAM ---
+ auth_pam "Notas DDAW2";
+ auth_pam_service_name "common-auth";
+
+ # --- Servir notas del alumno autenticado ---
+ location = /notas.md {
+ alias /var/www/api/data/$remote_user/notas.md;
+ default_type text/plain;
+ charset utf-8;
+ }
+
+ # --- Assets estáticos (viewer + marked) ---
+ location ~* \.(html|js)$ {
+ auth_pam off; # viewer.html y marked.min.js son públicos
+ expires 1h;
+ }
+
+ access_log /var/log/nginx/napi-access.log;
+ error_log /var/log/nginx/napi-error.log;
+}
+
+# Redirección HTTP → HTTPS
+server {
+ listen 80;
+ server_name notas.TU_DOMINIO;
+ return 301 https://$server_name$request_uri;
+}
+```
+
+```bash
+sudo ln -s /etc/nginx/sites-available/napi /etc/nginx/sites-enabled/
+sudo nginx -t && sudo systemctl reload nginx
+```
+
+### 6. Crear carpeta de datos para cada alumno
+
+```bash
+# Para un alumno:
+ALUMNO="alumno01"
+sudo mkdir -p /var/www/api/data/$ALUMNO
+sudo cp /var/www/api/data/_plantilla/notas.md /var/www/api/data/$ALUMNO/notas.md
+sudo chown -R www-data:www-data /var/www/api/data/$ALUMNO
+
+# Para todos los alumnos de una vez (si ya existen como usuarios del sistema):
+for user in $(getent group sftpusers | cut -d: -f4 | tr ',' ' '); do
+ sudo mkdir -p /var/www/api/data/$user
+ sudo cp /var/www/api/data/_plantilla/notas.md /var/www/api/data/$user/notas.md 2>/dev/null || true
+ sudo chown -R www-data:www-data /var/www/api/data/$user
+ echo "✅ $user"
+done
+```
+
+### 7. Verificar que funciona
+
+```bash
+# Probar autenticación y respuesta
+curl -u alumno01:SU_CONTRASEÑA -sk https://notas.TU_DOMINIO/notas.md | head -5
+
+# Debe devolver las primeras líneas del notas.md del alumno
+```
+
+---
+
+## Configurar sshfs en la máquina del profesor
+
+### Instalar sshfs
+
+```bash
+# Debian/Ubuntu
+sudo apt install sshfs
+
+# Fedora/RHEL
+sudo dnf install fuse-sshfs
+```
+
+### Crear punto de montaje
+
+```bash
+mkdir -p ~/napi-data
+```
+
+### Montar manualmente (prueba)
+
+```bash
+sshfs USUARIO@TU_SERVIDOR:/var/www/api/data ~/napi-data \
+ -o reconnect,ServerAliveInterval=15,ServerAliveCountMax=3
+```
+
+### Montaje persistente con systemd (recomendado)
+
+Crear `~/.config/systemd/user/home-TUUSUARIO-napi\x2ddata.mount`
+(sustituye `TUUSUARIO` por tu usuario real, ej: `fenix`):
+
+```ini
+[Unit]
+Description=napi-data → servidor:/var/www/api/data (sshfs)
+After=network-online.target
+
+[Mount]
+What=USUARIO@TU_SERVIDOR:/var/www/api/data
+Where=/home/TUUSUARIO/napi-data
+Type=fuse.sshfs
+Options=reconnect,ServerAliveInterval=15,ServerAliveCountMax=3
+
+[Install]
+WantedBy=default.target
+```
+
+```bash
+systemctl --user daemon-reload
+systemctl --user enable --now 'home-TUUSUARIO-napi\x2ddata.mount'
+
+# Verificar
+systemctl --user status 'home-TUUSUARIO-napi\x2ddata.mount'
+```
+
+> 💡 El nombre de la unit debe coincidir exactamente con la ruta del `Where`
+> (reemplazando `/` por `-` y los guiones por `\x2d`).
+
+---
+
+## Workflow del profesor
+
+```
+1. C-x C-f ~/napi-data/pablo/notas.md ← abrir en Emacs
+2. Editar feedback, notas, próximos pasos
+3. C-x C-s ← guardar
+4. Alumno refresca el navegador ← cambios visibles
+```
+
+**No hay paso 5.**
+
+---
+
+## Añadir un alumno nuevo
+
+```bash
+# En el servidor:
+ALUMNO="nuevo_alumno"
+sudo mkdir -p /var/www/api/data/$ALUMNO
+sudo cp /var/www/api/data/_plantilla/notas.md /var/www/api/data/$ALUMNO/notas.md
+sudo chown -R www-data:www-data /var/www/api/data/$ALUMNO
+
+# En la máquina del profesor (aparece automáticamente via sshfs):
+ls ~/napi-data/$ALUMNO/ # → notas.md
+# Editar con Emacs y personalizar
+```
+
+---
+
+## Formato del fichero notas.md
+
+```markdown
+# Notas — NombreAlumno
+
+> 🏫 **Módulo:** NOMBRE_MODULO
+> 📅 **Última actualización:** YYYY-MM-DD
+
+---
+
+## 📊 Resumen
+
+| Práctica | Título | Nota | Estado |
+|:---------|:-------|:----:|:------:|
+| P2.3 | Nginx via SFTP | 7/10 | ✅ |
+| P2.4 | HTTP y HTTPS | 8/10 | ✅ |
+| P2.7 | Multi-sitio | 9/10 | ✅ |
+
+---
+
+## P2.7 — Multi-sitio Web con Nginx
+
+**Nota: 9/10** · _Escaneado: 2026-02-19_
+
+NombreAlumno, [feedback personalizado].
+
+### Criterios
+
+| Criterio | Puntos | Estado |
+|:---------|:------:|:------:|
+| Hextris desplegado + HTTPS | 1,5/1,5 | ✅ |
+| Gzip | 1/1 | ✅ |
+| CSP correcta | 1/1,5 | ⚠️ unsafe-inline |
+
+### Próximos pasos
+
+1. Corregir CSP: eliminar `unsafe-inline`
+2. Subir capturas de verificación
+```
+
+Ver `_plantilla/notas.md` como punto de partida para nuevos alumnos.
+
+---
+
+## Ficheros de la app (en el servidor)
+
+### `viewer.html`
+
+App completa en ~40 líneas. Fetcha `/notas.md` (que Nginx resuelve al fichero
+del alumno autenticado) y lo renderiza con `marked.min.js`:
+
+```html
+
+
+
+
+
+ Notas
+
+
+
+ Cargando...
+
+
+
+
+```
+
+### `marked.min.js`
+
+Descargar de https://cdn.jsdelivr.net/npm/marked/marked.min.js y guardar como
+fichero local en `/var/www/api/marked.min.js`. No referenciar CDN externo
+(rompe la CSP y crea dependencia de terceros).
+
+---
+
+## Gestión del mount sshfs
+
+```bash
+# Estado
+systemctl --user status 'home-TUUSUARIO-napi\x2ddata.mount'
+
+# Montar
+systemctl --user start 'home-TUUSUARIO-napi\x2ddata.mount'
+
+# Desmontar
+systemctl --user stop 'home-TUUSUARIO-napi\x2ddata.mount'
+
+# Si se cuelga (mount zombie):
+fusermount -uz ~/napi-data
+systemctl --user start 'home-TUUSUARIO-napi\x2ddata.mount'
+```
+
+---
+
+## Troubleshooting
+
+| Síntoma | Causa probable | Solución |
+|:--------|:---------------|:---------|
+| `403 Forbidden` al acceder | www-data no está en grupo shadow | `sudo usermod -aG shadow www-data && sudo systemctl restart nginx` |
+| `401 Unauthorized` con credenciales correctas | PAM no configurado | Verificar que `auth_pam_service_name "common-auth"` existe en `/etc/pam.d/` |
+| `/notas.md` devuelve 404 | Carpeta del alumno no existe en `data/` | `sudo mkdir -p /var/www/api/data/$ALUMNO` |
+| sshfs mount desaparece | Pérdida de conexión SSH | La opción `reconnect` lo recupera solo; si no, `systemctl --user restart` |
+| El alumno ve las notas de otro | `$remote_user` vacío o PAM no activo | Verificar que `auth_pam` y `auth_pam_service_name` están en el bloque correcto |
+| `marked is not defined` | `marked.min.js` no accesible | Verificar que el fichero existe en `/var/www/api/` y tiene permisos de lectura |
+
+---
+
+## Seguridad
+
+- Cada alumno solo ve sus propias notas — Nginx resuelve el path con `$remote_user`
+- Sin ejecución de código en el servidor — todo es estático
+- `marked.min.js` local — sin dependencia de CDNs externos
+- Credenciales: las mismas que usa el alumno para subir archivos por SFTP
+- SSL/TLS obligatorio (redirección 301 desde HTTP)
+
+---
+
+## Historial
+
+| Fecha | Hito |
+|:------|:-----|
+| 2026-02-22 | MVP desplegado: sshfs + Nginx auth_pam + viewer.html + marked.js |
+| 2026-02-22 | notas.md generadas para los 19 alumnos de DDAW2 |
diff --git a/marked.min.js b/marked.min.js
new file mode 100644
index 0000000..b4e0d73
--- /dev/null
+++ b/marked.min.js
@@ -0,0 +1,69 @@
+/**
+ * marked v15.0.12 - a markdown parser
+ * Copyright (c) 2011-2025, Christopher Jeffrey. (MIT Licensed)
+ * https://github.com/markedjs/marked
+ */
+
+/**
+ * DO NOT EDIT THIS FILE
+ * The code in this file is generated from files in ./src/
+ */
+(function(g,f){if(typeof exports=="object"&&typeof module<"u"){module.exports=f()}else if("function"==typeof define && define.amd){define("marked",f)}else {g["marked"]=f()}}(typeof globalThis < "u" ? globalThis : typeof self < "u" ? self : this,function(){var exports={};var __exports=exports;var module={exports};
+"use strict";var H=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var Te=Object.getOwnPropertyNames;var we=Object.prototype.hasOwnProperty;var ye=(l,e)=>{for(var t in e)H(l,t,{get:e[t],enumerable:!0})},Re=(l,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of Te(e))!we.call(l,s)&&s!==t&&H(l,s,{get:()=>e[s],enumerable:!(n=be(e,s))||n.enumerable});return l};var Se=l=>Re(H({},"__esModule",{value:!0}),l);var kt={};ye(kt,{Hooks:()=>L,Lexer:()=>x,Marked:()=>E,Parser:()=>b,Renderer:()=>$,TextRenderer:()=>_,Tokenizer:()=>S,defaults:()=>w,getDefaults:()=>z,lexer:()=>ht,marked:()=>k,options:()=>it,parse:()=>pt,parseInline:()=>ct,parser:()=>ut,setOptions:()=>ot,use:()=>lt,walkTokens:()=>at});module.exports=Se(kt);function z(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}var w=z();function N(l){w=l}var I={exec:()=>null};function h(l,e=""){let t=typeof l=="string"?l:l.source,n={replace:(s,i)=>{let r=typeof i=="string"?i:i.source;return r=r.replace(m.caret,"$1"),t=t.replace(s,r),n},getRegex:()=>new RegExp(t,e)};return n}var m={codeRemoveIndent:/^(?: {1,4}| {0,3}\t)/gm,outputLinkReplace:/\\([\[\]])/g,indentCodeCompensation:/^(\s+)(?:```)/,beginningSpace:/^\s+/,endingHash:/#$/,startingSpaceChar:/^ /,endingSpaceChar:/ $/,nonSpaceChar:/[^ ]/,newLineCharGlobal:/\n/g,tabCharGlobal:/\t/g,multipleSpaceGlobal:/\s+/g,blankLine:/^[ \t]*$/,doubleBlankLine:/\n[ \t]*\n[ \t]*$/,blockquoteStart:/^ {0,3}>/,blockquoteSetextReplace:/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,blockquoteSetextReplace2:/^ {0,3}>[ \t]?/gm,listReplaceTabs:/^\t+/,listReplaceNesting:/^ {1,4}(?=( {4})*[^ ])/g,listIsTask:/^\[[ xX]\] /,listReplaceTask:/^\[[ xX]\] +/,anyLine:/\n.*\n/,hrefBrackets:/^<(.*)>$/,tableDelimiter:/[:|]/,tableAlignChars:/^\||\| *$/g,tableRowBlankLine:/\n[ \t]*$/,tableAlignRight:/^ *-+: *$/,tableAlignCenter:/^ *:-+: *$/,tableAlignLeft:/^ *:-+ *$/,startATag:/^/i,startPreScriptTag:/^<(pre|code|kbd|script)(\s|>)/i,endPreScriptTag:/^<\/(pre|code|kbd|script)(\s|>)/i,startAngleBracket:/^,endAngleBracket:/>$/,pedanticHrefTitle:/^([^'"]*[^\s])\s+(['"])(.*)\2/,unicodeAlphaNumeric:/[\p{L}\p{N}]/u,escapeTest:/[&<>"']/,escapeReplace:/[&<>"']/g,escapeTestNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,escapeReplaceNoEncode:/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/g,unescapeTest:/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig,caret:/(^|[^\[])\^/g,percentDecode:/%25/g,findPipe:/\|/g,splitPipe:/ \|/,slashPipe:/\\\|/g,carriageReturn:/\r\n|\r/g,spaceLine:/^ +$/gm,notSpaceStart:/^\S*/,endingNewline:/\n$/,listItemRegex:l=>new RegExp(`^( {0,3}${l})((?:[ ][^\\n]*)?(?:\\n|$))`),nextBulletRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ ][^\\n]*)?(?:\\n|$))`),hrRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),fencesBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}(?:\`\`\`|~~~)`),headingBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}#`),htmlBeginRegex:l=>new RegExp(`^ {0,${Math.min(3,l-1)}}<(?:[a-z].*>|!--)`,"i")},$e=/^(?:[ \t]*(?:\n|$))+/,_e=/^((?: {4}| {0,3}\t)[^\n]+(?:\n(?:[ \t]*(?:\n|$))*)?)+/,Le=/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,O=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,ze=/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,F=/(?:[*+-]|\d{1,9}[.)])/,ie=/^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\n {0,3}(=+|-+) *(?:\n+|$)/,oe=h(ie).replace(/bull/g,F).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/\|table/g,"").getRegex(),Me=h(ie).replace(/bull/g,F).replace(/blockCode/g,/(?: {4}| {0,3}\t)/).replace(/fences/g,/ {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g,/ {0,3}>/).replace(/heading/g,/ {0,3}#{1,6}/).replace(/html/g,/ {0,3}<[^\n>]+>\n/).replace(/table/g,/ {0,3}\|?(?:[:\- ]*\|)+[\:\- ]*\n/).getRegex(),Q=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,Pe=/^[^\n]+/,U=/(?!\s*\])(?:\\.|[^\[\]\\])+/,Ae=h(/^ {0,3}\[(label)\]: *(?:\n[ \t]*)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n[ \t]*)?| *\n[ \t]*)(title))? *(?:\n+|$)/).replace("label",U).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),Ee=h(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,F).getRegex(),v="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",K=/|$))/,Ce=h("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$)|(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n[ ]*)+\\n|$))","i").replace("comment",K).replace("tag",v).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),le=h(Q).replace("hr",O).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex(),Ie=h(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",le).getRegex(),X={blockquote:Ie,code:_e,def:Ae,fences:Le,heading:ze,hr:O,html:Ce,lheading:oe,list:Ee,newline:$e,paragraph:le,table:I,text:Pe},re=h("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",O).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code","(?: {4}| {0,3} )[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex(),Oe={...X,lheading:Me,table:re,paragraph:h(Q).replace("hr",O).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",re).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",v).getRegex()},Be={...X,html:h(`^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?\\1> *(?:\\n{2,}|\\s*$)| \\s]*)*?/?> *(?:\\n{2,}|\\s*$))`).replace("comment",K).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:I,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:h(Q).replace("hr",O).replace("heading",` *#{1,6} *[^
+]`).replace("lheading",oe).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},qe=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,ve=/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,ae=/^( {2,}|\\)\n(?!\s*$)/,De=/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\]*?>/g,ue=/^(?:\*+(?:((?!\*)punct)|[^\s*]))|^_+(?:((?!_)punct)|([^\s_]))/,je=h(ue,"u").replace(/punct/g,D).getRegex(),Fe=h(ue,"u").replace(/punct/g,pe).getRegex(),he="^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)punct(\\*+)(?=[\\s]|$)|notPunctSpace(\\*+)(?!\\*)(?=punctSpace|$)|(?!\\*)punctSpace(\\*+)(?=notPunctSpace)|[\\s](\\*+)(?!\\*)(?=punct)|(?!\\*)punct(\\*+)(?!\\*)(?=punct)|notPunctSpace(\\*+)(?=notPunctSpace)",Qe=h(he,"gu").replace(/notPunctSpace/g,ce).replace(/punctSpace/g,W).replace(/punct/g,D).getRegex(),Ue=h(he,"gu").replace(/notPunctSpace/g,He).replace(/punctSpace/g,Ge).replace(/punct/g,pe).getRegex(),Ke=h("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)punct(_+)(?=[\\s]|$)|notPunctSpace(_+)(?!_)(?=punctSpace|$)|(?!_)punctSpace(_+)(?=notPunctSpace)|[\\s](_+)(?!_)(?=punct)|(?!_)punct(_+)(?!_)(?=punct)","gu").replace(/notPunctSpace/g,ce).replace(/punctSpace/g,W).replace(/punct/g,D).getRegex(),Xe=h(/\\(punct)/,"gu").replace(/punct/g,D).getRegex(),We=h(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),Je=h(K).replace("(?:-->|$)","-->").getRegex(),Ve=h("^comment|^[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^").replace("comment",Je).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),q=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,Ye=h(/^!?\[(label)\]\(\s*(href)(?:(?:[ \t]*(?:\n[ \t]*)?)(title))?\s*\)/).replace("label",q).replace("href",/<(?:\\.|[^\n<>\\])+>|[^ \t\n\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),ke=h(/^!?\[(label)\]\[(ref)\]/).replace("label",q).replace("ref",U).getRegex(),ge=h(/^!?\[(ref)\](?:\[\])?/).replace("ref",U).getRegex(),et=h("reflink|nolink(?!\\()","g").replace("reflink",ke).replace("nolink",ge).getRegex(),J={_backpedal:I,anyPunctuation:Xe,autolink:We,blockSkip:Ne,br:ae,code:ve,del:I,emStrongLDelim:je,emStrongRDelimAst:Qe,emStrongRDelimUnd:Ke,escape:qe,link:Ye,nolink:ge,punctuation:Ze,reflink:ke,reflinkSearch:et,tag:Ve,text:De,url:I},tt={...J,link:h(/^!?\[(label)\]\((.*?)\)/).replace("label",q).getRegex(),reflink:h(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",q).getRegex()},j={...J,emStrongRDelimAst:Ue,emStrongLDelim:Fe,url:h(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,"i").replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])((?:\\.|[^\\])*?(?:\\.|[^\s~\\]))\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\":">",'"':""","'":"'"},fe=l=>st[l];function R(l,e){if(e){if(m.escapeTest.test(l))return l.replace(m.escapeReplace,fe)}else if(m.escapeTestNoEncode.test(l))return l.replace(m.escapeReplaceNoEncode,fe);return l}function V(l){try{l=encodeURI(l).replace(m.percentDecode,"%")}catch{return null}return l}function Y(l,e){let t=l.replace(m.findPipe,(i,r,o)=>{let a=!1,c=r;for(;--c>=0&&o[c]==="\\";)a=!a;return a?"|":" |"}),n=t.split(m.splitPipe),s=0;if(n[0].trim()||n.shift(),n.length>0&&!n.at(-1)?.trim()&&n.pop(),e)if(n.length>e)n.splice(e);else for(;n.length0?-2:-1}function me(l,e,t,n,s){let i=e.href,r=e.title||null,o=l[1].replace(s.other.outputLinkReplace,"$1");n.state.inLink=!0;let a={type:l[0].charAt(0)==="!"?"image":"link",raw:t,href:i,title:r,text:o,tokens:n.inlineTokens(o)};return n.state.inLink=!1,a}function rt(l,e,t){let n=l.match(t.other.indentCodeCompensation);if(n===null)return e;let s=n[1];return e.split(`
+`).map(i=>{let r=i.match(t.other.beginningSpace);if(r===null)return i;let[o]=r;return o.length>=s.length?i.slice(s.length):i}).join(`
+`)}var S=class{options;rules;lexer;constructor(e){this.options=e||w}space(e){let t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){let t=this.rules.block.code.exec(e);if(t){let n=t[0].replace(this.rules.other.codeRemoveIndent,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?n:A(n,`
+`)}}}fences(e){let t=this.rules.block.fences.exec(e);if(t){let n=t[0],s=rt(n,t[3]||"",this.rules);return{type:"code",raw:n,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:s}}}heading(e){let t=this.rules.block.heading.exec(e);if(t){let n=t[2].trim();if(this.rules.other.endingHash.test(n)){let s=A(n,"#");(this.options.pedantic||!s||this.rules.other.endingSpaceChar.test(s))&&(n=s.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:n,tokens:this.lexer.inline(n)}}}hr(e){let t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:A(t[0],`
+`)}}blockquote(e){let t=this.rules.block.blockquote.exec(e);if(t){let n=A(t[0],`
+`).split(`
+`),s="",i="",r=[];for(;n.length>0;){let o=!1,a=[],c;for(c=0;c1,i={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");let r=this.rules.other.listItemRegex(n),o=!1;for(;e;){let c=!1,p="",u="";if(!(t=r.exec(e))||this.rules.block.hr.test(e))break;p=t[0],e=e.substring(p.length);let d=t[2].split(`
+`,1)[0].replace(this.rules.other.listReplaceTabs,Z=>" ".repeat(3*Z.length)),g=e.split(`
+`,1)[0],T=!d.trim(),f=0;if(this.options.pedantic?(f=2,u=d.trimStart()):T?f=t[1].length+1:(f=t[2].search(this.rules.other.nonSpaceChar),f=f>4?1:f,u=d.slice(f),f+=t[1].length),T&&this.rules.other.blankLine.test(g)&&(p+=g+`
+`,e=e.substring(g.length+1),c=!0),!c){let Z=this.rules.other.nextBulletRegex(f),te=this.rules.other.hrRegex(f),ne=this.rules.other.fencesBeginRegex(f),se=this.rules.other.headingBeginRegex(f),xe=this.rules.other.htmlBeginRegex(f);for(;e;){let G=e.split(`
+`,1)[0],C;if(g=G,this.options.pedantic?(g=g.replace(this.rules.other.listReplaceNesting," "),C=g):C=g.replace(this.rules.other.tabCharGlobal," "),ne.test(g)||se.test(g)||xe.test(g)||Z.test(g)||te.test(g))break;if(C.search(this.rules.other.nonSpaceChar)>=f||!g.trim())u+=`
+`+C.slice(f);else{if(T||d.replace(this.rules.other.tabCharGlobal," ").search(this.rules.other.nonSpaceChar)>=4||ne.test(d)||se.test(d)||te.test(d))break;u+=`
+`+g}!T&&!g.trim()&&(T=!0),p+=G+`
+`,e=e.substring(G.length+1),d=C.slice(f)}}i.loose||(o?i.loose=!0:this.rules.other.doubleBlankLine.test(p)&&(o=!0));let y=null,ee;this.options.gfm&&(y=this.rules.other.listIsTask.exec(u),y&&(ee=y[0]!=="[ ] ",u=u.replace(this.rules.other.listReplaceTask,""))),i.items.push({type:"list_item",raw:p,task:!!y,checked:ee,loose:!1,text:u,tokens:[]}),i.raw+=p}let a=i.items.at(-1);if(a)a.raw=a.raw.trimEnd(),a.text=a.text.trimEnd();else return;i.raw=i.raw.trimEnd();for(let c=0;cd.type==="space"),u=p.length>0&&p.some(d=>this.rules.other.anyLine.test(d.raw));i.loose=u}if(i.loose)for(let c=0;c({text:a,tokens:this.lexer.inline(a),header:!1,align:r.align[c]})));return r}}lheading(e){let t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:t[2].charAt(0)==="="?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){let t=this.rules.block.paragraph.exec(e);if(t){let n=t[1].charAt(t[1].length-1)===`
+`?t[1].slice(0,-1):t[1];return{type:"paragraph",raw:t[0],text:n,tokens:this.lexer.inline(n)}}}text(e){let t=this.rules.block.text.exec(e);if(t)return{type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){let t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:t[1]}}tag(e){let t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&this.rules.other.startATag.test(t[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&this.rules.other.endATag.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&this.rules.other.startPreScriptTag.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&this.rules.other.endPreScriptTag.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){let t=this.rules.inline.link.exec(e);if(t){let n=t[2].trim();if(!this.options.pedantic&&this.rules.other.startAngleBracket.test(n)){if(!this.rules.other.endAngleBracket.test(n))return;let r=A(n.slice(0,-1),"\\");if((n.length-r.length)%2===0)return}else{let r=de(t[2],"()");if(r===-2)return;if(r>-1){let a=(t[0].indexOf("!")===0?5:4)+t[1].length+r;t[2]=t[2].substring(0,r),t[0]=t[0].substring(0,a).trim(),t[3]=""}}let s=t[2],i="";if(this.options.pedantic){let r=this.rules.other.pedanticHrefTitle.exec(s);r&&(s=r[1],i=r[3])}else i=t[3]?t[3].slice(1,-1):"";return s=s.trim(),this.rules.other.startAngleBracket.test(s)&&(this.options.pedantic&&!this.rules.other.endAngleBracket.test(n)?s=s.slice(1):s=s.slice(1,-1)),me(t,{href:s&&s.replace(this.rules.inline.anyPunctuation,"$1"),title:i&&i.replace(this.rules.inline.anyPunctuation,"$1")},t[0],this.lexer,this.rules)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){let s=(n[2]||n[1]).replace(this.rules.other.multipleSpaceGlobal," "),i=t[s.toLowerCase()];if(!i){let r=n[0].charAt(0);return{type:"text",raw:r,text:r}}return me(n,i,n[0],this.lexer,this.rules)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s||s[3]&&n.match(this.rules.other.unicodeAlphaNumeric))return;if(!(s[1]||s[2]||"")||!n||this.rules.inline.punctuation.exec(n)){let r=[...s[0]].length-1,o,a,c=r,p=0,u=s[0][0]==="*"?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(u.lastIndex=0,t=t.slice(-1*e.length+r);(s=u.exec(t))!=null;){if(o=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!o)continue;if(a=[...o].length,s[3]||s[4]){c+=a;continue}else if((s[5]||s[6])&&r%3&&!((r+a)%3)){p+=a;continue}if(c-=a,c>0)continue;a=Math.min(a,a+c+p);let d=[...s[0]][0].length,g=e.slice(0,r+s.index+d+a);if(Math.min(r,a)%2){let f=g.slice(1,-1);return{type:"em",raw:g,text:f,tokens:this.lexer.inlineTokens(f)}}let T=g.slice(2,-2);return{type:"strong",raw:g,text:T,tokens:this.lexer.inlineTokens(T)}}}}codespan(e){let t=this.rules.inline.code.exec(e);if(t){let n=t[2].replace(this.rules.other.newLineCharGlobal," "),s=this.rules.other.nonSpaceChar.test(n),i=this.rules.other.startingSpaceChar.test(n)&&this.rules.other.endingSpaceChar.test(n);return s&&i&&(n=n.substring(1,n.length-1)),{type:"codespan",raw:t[0],text:n}}}br(e){let t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){let t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e){let t=this.rules.inline.autolink.exec(e);if(t){let n,s;return t[2]==="@"?(n=t[1],s="mailto:"+n):(n=t[1],s=n),{type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let n,s;if(t[2]==="@")n=t[0],s="mailto:"+n;else{let i;do i=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??"";while(i!==t[0]);n=t[0],t[1]==="www."?s="http://"+t[0]:s=t[0]}return{type:"link",raw:t[0],text:n,href:s,tokens:[{type:"text",raw:n,text:n}]}}}inlineText(e){let t=this.rules.inline.text.exec(e);if(t){let n=this.lexer.state.inRawBlock;return{type:"text",raw:t[0],text:t[0],escaped:n}}}};var x=class l{tokens;options;state;tokenizer;inlineQueue;constructor(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||w,this.options.tokenizer=this.options.tokenizer||new S,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};let t={other:m,block:B.normal,inline:P.normal};this.options.pedantic?(t.block=B.pedantic,t.inline=P.pedantic):this.options.gfm&&(t.block=B.gfm,this.options.breaks?t.inline=P.breaks:t.inline=P.gfm),this.tokenizer.rules=t}static get rules(){return{block:B,inline:P}}static lex(e,t){return new l(t).lex(e)}static lexInline(e,t){return new l(t).inlineTokens(e)}lex(e){e=e.replace(m.carriageReturn,`
+`),this.blockTokens(e,this.tokens);for(let t=0;t(s=r.call({lexer:this},e,t))?(e=e.substring(s.raw.length),t.push(s),!0):!1))continue;if(s=this.tokenizer.space(e)){e=e.substring(s.raw.length);let r=t.at(-1);s.raw.length===1&&r!==void 0?r.raw+=`
+`:t.push(s);continue}if(s=this.tokenizer.code(e)){e=e.substring(s.raw.length);let r=t.at(-1);r?.type==="paragraph"||r?.type==="text"?(r.raw+=`
+`+s.raw,r.text+=`
+`+s.text,this.inlineQueue.at(-1).src=r.text):t.push(s);continue}if(s=this.tokenizer.fences(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.heading(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.hr(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.blockquote(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.list(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.html(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.def(e)){e=e.substring(s.raw.length);let r=t.at(-1);r?.type==="paragraph"||r?.type==="text"?(r.raw+=`
+`+s.raw,r.text+=`
+`+s.raw,this.inlineQueue.at(-1).src=r.text):this.tokens.links[s.tag]||(this.tokens.links[s.tag]={href:s.href,title:s.title});continue}if(s=this.tokenizer.table(e)){e=e.substring(s.raw.length),t.push(s);continue}if(s=this.tokenizer.lheading(e)){e=e.substring(s.raw.length),t.push(s);continue}let i=e;if(this.options.extensions?.startBlock){let r=1/0,o=e.slice(1),a;this.options.extensions.startBlock.forEach(c=>{a=c.call({lexer:this},o),typeof a=="number"&&a>=0&&(r=Math.min(r,a))}),r<1/0&&r>=0&&(i=e.substring(0,r+1))}if(this.state.top&&(s=this.tokenizer.paragraph(i))){let r=t.at(-1);n&&r?.type==="paragraph"?(r.raw+=`
+`+s.raw,r.text+=`
+`+s.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=r.text):t.push(s),n=i.length!==e.length,e=e.substring(s.raw.length);continue}if(s=this.tokenizer.text(e)){e=e.substring(s.raw.length);let r=t.at(-1);r?.type==="text"?(r.raw+=`
+`+s.raw,r.text+=`
+`+s.text,this.inlineQueue.pop(),this.inlineQueue.at(-1).src=r.text):t.push(s);continue}if(e){let r="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(r);break}else throw new Error(r)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let n=e,s=null;if(this.tokens.links){let o=Object.keys(this.tokens.links);if(o.length>0)for(;(s=this.tokenizer.rules.inline.reflinkSearch.exec(n))!=null;)o.includes(s[0].slice(s[0].lastIndexOf("[")+1,-1))&&(n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;(s=this.tokenizer.rules.inline.anyPunctuation.exec(n))!=null;)n=n.slice(0,s.index)+"++"+n.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);for(;(s=this.tokenizer.rules.inline.blockSkip.exec(n))!=null;)n=n.slice(0,s.index)+"["+"a".repeat(s[0].length-2)+"]"+n.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);let i=!1,r="";for(;e;){i||(r=""),i=!1;let o;if(this.options.extensions?.inline?.some(c=>(o=c.call({lexer:this},e,t))?(e=e.substring(o.raw.length),t.push(o),!0):!1))continue;if(o=this.tokenizer.escape(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.tag(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.link(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.reflink(e,this.tokens.links)){e=e.substring(o.raw.length);let c=t.at(-1);o.type==="text"&&c?.type==="text"?(c.raw+=o.raw,c.text+=o.text):t.push(o);continue}if(o=this.tokenizer.emStrong(e,n,r)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.codespan(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.br(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.del(e)){e=e.substring(o.raw.length),t.push(o);continue}if(o=this.tokenizer.autolink(e)){e=e.substring(o.raw.length),t.push(o);continue}if(!this.state.inLink&&(o=this.tokenizer.url(e))){e=e.substring(o.raw.length),t.push(o);continue}let a=e;if(this.options.extensions?.startInline){let c=1/0,p=e.slice(1),u;this.options.extensions.startInline.forEach(d=>{u=d.call({lexer:this},p),typeof u=="number"&&u>=0&&(c=Math.min(c,u))}),c<1/0&&c>=0&&(a=e.substring(0,c+1))}if(o=this.tokenizer.inlineText(a)){e=e.substring(o.raw.length),o.raw.slice(-1)!=="_"&&(r=o.raw.slice(-1)),i=!0;let c=t.at(-1);c?.type==="text"?(c.raw+=o.raw,c.text+=o.text):t.push(o);continue}if(e){let c="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(c);break}else throw new Error(c)}}return t}};var $=class{options;parser;constructor(e){this.options=e||w}space(e){return""}code({text:e,lang:t,escaped:n}){let s=(t||"").match(m.notSpaceStart)?.[0],i=e.replace(m.endingNewline,"")+`
+`;return s?''+(n?i:R(i,!0))+`
+`:""+(n?i:R(i,!0))+`
+`}blockquote({tokens:e}){return`
+${this.parser.parse(e)}
+`}html({text:e}){return e}heading({tokens:e,depth:t}){return`${this.parser.parseInline(e)}
+`}hr(e){return`
+`}list(e){let t=e.ordered,n=e.start,s="";for(let o=0;o
+`+s+""+i+`>
+`}listitem(e){let t="";if(e.task){let n=this.checkbox({checked:!!e.checked});e.loose?e.tokens[0]?.type==="paragraph"?(e.tokens[0].text=n+" "+e.tokens[0].text,e.tokens[0].tokens&&e.tokens[0].tokens.length>0&&e.tokens[0].tokens[0].type==="text"&&(e.tokens[0].tokens[0].text=n+" "+R(e.tokens[0].tokens[0].text),e.tokens[0].tokens[0].escaped=!0)):e.tokens.unshift({type:"text",raw:n+" ",text:n+" ",escaped:!0}):t+=n+" "}return t+=this.parser.parse(e.tokens,!!e.loose),`${t}
+`}checkbox({checked:e}){return" '}paragraph({tokens:e}){return`${this.parser.parseInline(e)}
+`}table(e){let t="",n="";for(let i=0;i${s}`),`
+`}tablerow({text:e}){return`
+${e}
+`}tablecell(e){let t=this.parser.parseInline(e.tokens),n=e.header?"th":"td";return(e.align?`<${n} align="${e.align}">`:`<${n}>`)+t+`${n}>
+`}strong({tokens:e}){return`${this.parser.parseInline(e)} `}em({tokens:e}){return`${this.parser.parseInline(e)} `}codespan({text:e}){return`${R(e,!0)}`}br(e){return" "}del({tokens:e}){return`${this.parser.parseInline(e)}`}link({href:e,title:t,tokens:n}){let s=this.parser.parseInline(n),i=V(e);if(i===null)return s;e=i;let r='"+s+" ",r}image({href:e,title:t,text:n,tokens:s}){s&&(n=this.parser.parseInline(s,this.parser.textRenderer));let i=V(e);if(i===null)return R(n);e=i;let r=` ",r}text(e){return"tokens"in e&&e.tokens?this.parser.parseInline(e.tokens):"escaped"in e&&e.escaped?e.text:R(e.text)}};var _=class{strong({text:e}){return e}em({text:e}){return e}codespan({text:e}){return e}del({text:e}){return e}html({text:e}){return e}text({text:e}){return e}link({text:e}){return""+e}image({text:e}){return""+e}br(){return""}};var b=class l{options;renderer;textRenderer;constructor(e){this.options=e||w,this.options.renderer=this.options.renderer||new $,this.renderer=this.options.renderer,this.renderer.options=this.options,this.renderer.parser=this,this.textRenderer=new _}static parse(e,t){return new l(t).parse(e)}static parseInline(e,t){return new l(t).parseInline(e)}parse(e,t=!0){let n="";for(let s=0;s{let o=i[r].flat(1/0);n=n.concat(this.walkTokens(o,t))}):i.tokens&&(n=n.concat(this.walkTokens(i.tokens,t)))}}return n}use(...e){let t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach(n=>{let s={...n};if(s.async=this.defaults.async||s.async||!1,n.extensions&&(n.extensions.forEach(i=>{if(!i.name)throw new Error("extension name required");if("renderer"in i){let r=t.renderers[i.name];r?t.renderers[i.name]=function(...o){let a=i.renderer.apply(this,o);return a===!1&&(a=r.apply(this,o)),a}:t.renderers[i.name]=i.renderer}if("tokenizer"in i){if(!i.level||i.level!=="block"&&i.level!=="inline")throw new Error("extension level must be 'block' or 'inline'");let r=t[i.level];r?r.unshift(i.tokenizer):t[i.level]=[i.tokenizer],i.start&&(i.level==="block"?t.startBlock?t.startBlock.push(i.start):t.startBlock=[i.start]:i.level==="inline"&&(t.startInline?t.startInline.push(i.start):t.startInline=[i.start]))}"childTokens"in i&&i.childTokens&&(t.childTokens[i.name]=i.childTokens)}),s.extensions=t),n.renderer){let i=this.defaults.renderer||new $(this.defaults);for(let r in n.renderer){if(!(r in i))throw new Error(`renderer '${r}' does not exist`);if(["options","parser"].includes(r))continue;let o=r,a=n.renderer[o],c=i[o];i[o]=(...p)=>{let u=a.apply(i,p);return u===!1&&(u=c.apply(i,p)),u||""}}s.renderer=i}if(n.tokenizer){let i=this.defaults.tokenizer||new S(this.defaults);for(let r in n.tokenizer){if(!(r in i))throw new Error(`tokenizer '${r}' does not exist`);if(["options","rules","lexer"].includes(r))continue;let o=r,a=n.tokenizer[o],c=i[o];i[o]=(...p)=>{let u=a.apply(i,p);return u===!1&&(u=c.apply(i,p)),u}}s.tokenizer=i}if(n.hooks){let i=this.defaults.hooks||new L;for(let r in n.hooks){if(!(r in i))throw new Error(`hook '${r}' does not exist`);if(["options","block"].includes(r))continue;let o=r,a=n.hooks[o],c=i[o];L.passThroughHooks.has(r)?i[o]=p=>{if(this.defaults.async)return Promise.resolve(a.call(i,p)).then(d=>c.call(i,d));let u=a.call(i,p);return c.call(i,u)}:i[o]=(...p)=>{let u=a.apply(i,p);return u===!1&&(u=c.apply(i,p)),u}}s.hooks=i}if(n.walkTokens){let i=this.defaults.walkTokens,r=n.walkTokens;s.walkTokens=function(o){let a=[];return a.push(r.call(this,o)),i&&(a=a.concat(i.call(this,o))),a}}this.defaults={...this.defaults,...s}}),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return x.lex(e,t??this.defaults)}parser(e,t){return b.parse(e,t??this.defaults)}parseMarkdown(e){return(n,s)=>{let i={...s},r={...this.defaults,...i},o=this.onError(!!r.silent,!!r.async);if(this.defaults.async===!0&&i.async===!1)return o(new Error("marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise."));if(typeof n>"u"||n===null)return o(new Error("marked(): input parameter is undefined or null"));if(typeof n!="string")return o(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));r.hooks&&(r.hooks.options=r,r.hooks.block=e);let a=r.hooks?r.hooks.provideLexer():e?x.lex:x.lexInline,c=r.hooks?r.hooks.provideParser():e?b.parse:b.parseInline;if(r.async)return Promise.resolve(r.hooks?r.hooks.preprocess(n):n).then(p=>a(p,r)).then(p=>r.hooks?r.hooks.processAllTokens(p):p).then(p=>r.walkTokens?Promise.all(this.walkTokens(p,r.walkTokens)).then(()=>p):p).then(p=>c(p,r)).then(p=>r.hooks?r.hooks.postprocess(p):p).catch(o);try{r.hooks&&(n=r.hooks.preprocess(n));let p=a(n,r);r.hooks&&(p=r.hooks.processAllTokens(p)),r.walkTokens&&this.walkTokens(p,r.walkTokens);let u=c(p,r);return r.hooks&&(u=r.hooks.postprocess(u)),u}catch(p){return o(p)}}}onError(e,t){return n=>{if(n.message+=`
+Please report this to https://github.com/markedjs/marked.`,e){let s="An error occurred:
"+R(n.message+"",!0)+" ";return t?Promise.resolve(s):s}if(t)return Promise.reject(n);throw n}}};var M=new E;function k(l,e){return M.parse(l,e)}k.options=k.setOptions=function(l){return M.setOptions(l),k.defaults=M.defaults,N(k.defaults),k};k.getDefaults=z;k.defaults=w;k.use=function(...l){return M.use(...l),k.defaults=M.defaults,N(k.defaults),k};k.walkTokens=function(l,e){return M.walkTokens(l,e)};k.parseInline=M.parseInline;k.Parser=b;k.parser=b.parse;k.Renderer=$;k.TextRenderer=_;k.Lexer=x;k.lexer=x.lex;k.Tokenizer=S;k.Hooks=L;k.parse=k;var it=k.options,ot=k.setOptions,lt=k.use,at=k.walkTokens,ct=k.parseInline,pt=k,ut=b.parse,ht=x.lex;
+
+if(__exports != exports)module.exports = exports;return module.exports}));
diff --git a/viewer.html b/viewer.html
new file mode 100644
index 0000000..5aa249c
--- /dev/null
+++ b/viewer.html
@@ -0,0 +1,29 @@
+
+
+
+
+
+ Mis Notas
+
+
+
+
+ Cargando...
+
+
+