parent
906f9638b3
commit
cc6091c7a0
195 changed files with 1894 additions and 983 deletions
50
.eleventy.js
Normal file
50
.eleventy.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
const { basename } = require("path");
|
||||
const { EleventyHtmlBasePlugin } = require("@11ty/eleventy");
|
||||
const automaticNoopener = require("eleventy-plugin-automatic-noopener");
|
||||
const markdownItWikilinks = require("markdown-it-wikilinks")({
|
||||
uriSuffix: "",
|
||||
postProcessPagePath: (path) => path,
|
||||
postProcessLabel: (path) => basename(path).match(/^(?:(?:\d{4})-(?:\d{2})-(?:\d{2})-)?(.+)$/)[1],
|
||||
relativeBaseURL: "../",
|
||||
});
|
||||
const { formatDate } = require("./helpers/date");
|
||||
|
||||
/**
|
||||
* @param {import("@11ty/eleventy").UserConfig} eleventyConfig
|
||||
*/
|
||||
module.exports = function config(eleventyConfig) {
|
||||
eleventyConfig.addPassthroughCopy("drip.css");
|
||||
eleventyConfig.addPassthroughCopy("cowboy.svg");
|
||||
eleventyConfig.addPassthroughCopy("status/*");
|
||||
eleventyConfig.addPassthroughCopy("x/**/*.png");
|
||||
eleventyConfig.addPassthroughCopy("x/**/*.jpg");
|
||||
eleventyConfig.addPassthroughCopy("x/**/*.mp4");
|
||||
eleventyConfig.addPassthroughCopy("bookmarks/**/*.png");
|
||||
eleventyConfig.addPassthroughCopy("bookmarks/**/*.jpg");
|
||||
eleventyConfig.addPassthroughCopy("bookmarks/**/*.mp4");
|
||||
|
||||
eleventyConfig.addPlugin(EleventyHtmlBasePlugin);
|
||||
eleventyConfig.addPlugin(automaticNoopener, {
|
||||
noreferrer: false,
|
||||
});
|
||||
|
||||
eleventyConfig.amendLibrary("md", (mdLib) => mdLib.use(markdownItWikilinks));
|
||||
|
||||
eleventyConfig.addCollection("x", (collectionApi) => collectionApi.getFilteredByGlob("x/**/*"));
|
||||
|
||||
eleventyConfig.addShortcode(
|
||||
"dateToISO",
|
||||
/** @param {Date} date */ (date) => date.toISOString().slice(0, 10)
|
||||
);
|
||||
eleventyConfig.addShortcode("formatDate", formatDate);
|
||||
eleventyConfig.addShortcode("relativeLink", (link, baseUrl) => new URL(link, baseUrl).toString());
|
||||
|
||||
// eleventyConfig.addShortcode("formatDateish", formatDateish);
|
||||
// eleventyConfig.addShortcode("dateishToElement", dateishToElement);
|
||||
|
||||
return {
|
||||
dir: {
|
||||
output: "build",
|
||||
},
|
||||
};
|
||||
};
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,7 +1,4 @@
|
|||
build/
|
||||
node_modules/
|
||||
build-js/
|
||||
.env
|
||||
cache/
|
||||
rootfs/
|
||||
.pnpm-store/
|
||||
|
|
1
.npmrc
1
.npmrc
|
@ -1 +0,0 @@
|
|||
@nulo:registry=https://gitea.nulo.in/api/packages/nulo/npm/
|
|
@ -1,38 +0,0 @@
|
|||
_[Parte 2](2023-04-30%20Donweb%20quiere%20tu%20cripto.html)_
|
||||
|
||||
Hace unos días compre el "Cloud Server" (VPS) más barato que ofrece [[Donweb]] para experimentar ya que no había visto hosting en Argentina tan barato antes. No ofrecían la posibilidad de bootear distros alternativas a las que te ofrecen (Debian, Ubuntu, CentOS y Rocky) que me pareció raro, pero todo se puede hackear.
|
||||
|
||||
Me pareció raro/sospechoso que la instalación de Debian por defecto venía con las llaves SSH de muchisimxs empleadxs de Donweb en el authorized_keys de root dandoles acceso de superusuario, por lo que las borré.
|
||||
|
||||
Bootié una imágen de otro de mis proyectos experimentales, [define-alpine](https://gitea.nulo.in/Nulo/define-alpine), ya que quería ver que tan complicado era hacerlo funcionar en un entorno poco flexible como este. Por las 23 horas, lo logré, mandando esta captura de pantalla de victoria a un amigo:
|
||||
|
||||
![Captura de pantalla de una terminal de Linux con una sesión recién iniciada](2022-11-18%20Donweb%20es%20ridículo.md-captura-pre.jpg)
|
||||
|
||||
Me fui a dormir victorioso. Al día siguiente, por las 10 de la mañana, recibo este mail:
|
||||
|
||||
>Buenos días! como estas? espero que te encuentres muy bien! Tomo contacto contigo en esta ocasión para informarte que deberás re-crear el cloud correspondiente ya que has Instalado otro SO arriba de la imagen provista y no esta permitido.
|
||||
>
|
||||
>Saludos cordiales,
|
||||
>
|
||||
>Quedo a tu disposición y te agradezco califiques mi respuesta porque nos ayudará a mejorar la calidad de atención.
|
||||
>
|
||||
><pre>---------------------------------------------</pre><br>
|
||||
>[CENSURADO]<br>
|
||||
>Cloud & IaaS Technical Support - Donweb.cloud<br>
|
||||
><pre>---------------------------------------------</pre>
|
||||
|
||||
En ese momento estaba encerrado en una institución educativa, pero mi amigo descubrió que efectivamente sus terminos y condiciones lo prohibian entre otras cosas.
|
||||
|
||||
>Se incluye en este punto también cualquier otra información que DonWeb by Dattatec considere inapropiada según su absoluto y exclusivo criterio. Cualquier uso indebido de los servicios autorizará a DonWeb by Dattatec a la suspensión o eliminación de los servicios contratados y sus contenidos sin previo aviso, no haciéndose responsable DonWeb by Dattatec por cualquier pérdida que esto implique.
|
||||
|
||||
>El servidor deberá responder a SNMP (http://es.wikipedia.org/wiki/Simple_Network_Management_Protocol) desde ciertas IPs utilizadas por DonWeb by Dattatec para monitoreo del servicio las cuales son asignadas en la configuracion al momento del alta. El cliente no deberá desinstalar el servicio SNMP ni modificar su configuracion.
|
||||
|
||||
>DonWeb by Dattatec se reserva el derecho de suspender el servicio en cualquier momento en caso de detectar alguna anormalidad en las configuraciones antes mencionadas y no poder acceder al servidor para realizar las correcciones necesarias.
|
||||
|
||||
>IMPORTANTE: Una vez adquirido el Cloud Server, el cliente tiene la posibilidad de instalar cualquier imagen de los SO ofrecidos que se ajuste a sus necesidades. No obstante, el cliente debe abstenerse de instalar (o pisar una instalación) con una distribución y/o Sistema Operativo distinto a los ofrecidos en el catálogo de imágenes de DonWeb. DonWeb se reserva el derecho de suspender sin previo aviso el servicio en caso que se detecte lo antes mencionado o cualquier acción que comprometa la seguridad e integridad del servicio o la compañía.
|
||||
|
||||
DonYuta o RatiWeb, bue. Cuando logre escapar de dicha institución educativa y llegué a mi computador portable, descubrí que Donweb se había tomado la libertad de entrar al VNC de mi servidor a clavarse unos comandos:
|
||||
|
||||
![Captura de pantalla de una terminal de Linux con varios comandos consultando información sobre el sistema operativo que corría, entre otras cosas](2022-11-18%20Donweb%20es%20ridículo.md-captura-post.jpg)
|
||||
|
||||
No recomiendo.
|
1
404.md
1
404.md
|
@ -1 +0,0 @@
|
|||
No encontré esta página... Quizás me podrías [avisar](Contacto.html). o/
|
|
@ -1,3 +0,0 @@
|
|||
![Foto del Atreus v1 de frente](Atreus%20v1.md-frente.jpg)
|
||||
|
||||
![Foto del Atreus v1 de atrás, exponiendo sus cables interiores](Atreus%20v1.md-atrás.jpg)
|
|
@ -1,10 +0,0 @@
|
|||
[MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme)
|
||||
|
||||
Es una propiedad de CSS que indica en que colores se puede renderizar tu sitio. Si especificas `color-scheme: dark`, los navegadores automáticamente cambian los colores del fondo, el texto, los inputs, etc para ajustarse a eso.
|
||||
|
||||
Sin embargo, Safari elije colores pésimos:
|
||||
|
||||
<figure>
|
||||
<img src="./CSS:%20color-scheme-nulo.ar%20coso.jpg">
|
||||
<figcaption>nulo.ar antes de que especifique colores para los links</figcaption>
|
||||
</figure>
|
156
Caddyfile
Normal file
156
Caddyfile
Normal file
|
@ -0,0 +1,156 @@
|
|||
{
|
||||
http_port 8080
|
||||
}
|
||||
|
||||
localhost:8443 {
|
||||
log
|
||||
file_server browse
|
||||
root * ./build
|
||||
|
||||
redir "/Microcontrolador (teclados mecánicos).html" "/x/Microcontrolador%20(teclados%20mec%C3%A1nicos)/"
|
||||
redir "/Monitoreo de censura de Internet.html" "/x/Monitoreo%20de%20censura%20de%20Internet/"
|
||||
redir "/Mozilla.html" "/x/Mozilla/"
|
||||
redir "/2022-06-08 Necesitamos seguridad colectiva.html" "/x/2022-06-08-Necesitamos%20seguridad%20colectiva/"
|
||||
redir "/2022-07-13.html" "/x/2022-07-13/"
|
||||
redir "/2022-07-16.html" "/x/2022-07-16/"
|
||||
redir "/2022-10-15 Analisis de la extracción de datos del teléfono de Fernando André Sabag Montiel.html" "/x/2022-10-15-Analisis%20de%20la%20extracci%C3%B3n%20de%20datos%20del%20tel%C3%A9fono%20de%20Fernando%20Andr%C3%A9%20Sabag%20Montiel/"
|
||||
redir "/2022-10-30 Bugs de accesibilidad.html" "/x/2022-10-30-Bugs%20de%20accesibilidad/"
|
||||
redir "/2022-11-18 Donweb es ridículo.html" "/x/2022-11-18-Donweb%20es%20rid%C3%ADculo/"
|
||||
redir "/2023-04-30 Donweb quiere tu cripto.html" "/x/2023-04-30-Donweb%20quiere%20tu%20cripto/"
|
||||
redir "/404.html" "/x/404/"
|
||||
redir "/Activismo Gordo.html" "/x/Activismo%20Gordo/"
|
||||
redir "/Aesthetic.html" "/x/Aesthetic/"
|
||||
redir "/Alimentación.html" "/x/Alimentaci%C3%B3n/"
|
||||
redir "/Alpine Linux.html" "/x/Alpine%20Linux/"
|
||||
redir "/Android.html" "/x/Android/"
|
||||
redir "/Android Auto.html" "/x/Android%20Auto/"
|
||||
redir "/Android seguro.html" "/x/Android%20seguro/"
|
||||
redir "/Antiderechos de autorx.html" "/x/Antiderechos%20de%20autorx/"
|
||||
redir "/Aprender.html" "/x/Aprender/"
|
||||
redir "/Archivar los archivos de la dictadura militar.html" "/x/Archivar%20los%20archivos%20de%20la%20dictadura%20militar/"
|
||||
redir "/2023-02-05 Vergüenza algorítmica.html" "/x/2023-02-05-Verg%C3%BCenza%20algor%C3%ADtmica/"
|
||||
redir "/Arreglando bugs ajenos.html" "/x/2021-10-11-Arreglando%20bugs%20ajenos/"
|
||||
redir "/Atreus v1.html" "/x/Atreus%20v1/"
|
||||
redir "/Atreus v2.html" "/x/Atreus%20v2/"
|
||||
redir "/BitTorrent.html" "/x/BitTorrent/"
|
||||
redir "/BitTorrent v2.html" "/x/BitTorrent%20v2/"
|
||||
redir "/Bluetooth.html" "/x/Bluetooth/"
|
||||
redir "/Bookmarklets.html" "/x/Bookmarklets/"
|
||||
redir "/Booteables.html" "/x/Booteables/"
|
||||
redir "/Boox T68.html" "/x/Boox%20T68/"
|
||||
redir "/Burn Book.html" "/x/Burn%20Book/"
|
||||
redir "/C.html" "/x/C/"
|
||||
redir "/CHINESE GOD OIL.html" "/x/CHINESE%20GOD%20OIL/"
|
||||
redir "/Chromium.html" "/x/Chromium/"
|
||||
redir "/Cocina.html" "/x/Cocina/"
|
||||
redir "/Códigos QR.html" "/x/C%C3%B3digos%20QR/"
|
||||
redir "/Comics.html" "/x/Comics/"
|
||||
redir "/Cooperativas.html" "/x/Cooperativas/"
|
||||
redir "/Cosas.html" "/x/Cosas/"
|
||||
redir "/CRDT.html" "/x/CRDT/"
|
||||
redir "/CSS: color-scheme.html" "/x/CSS/"
|
||||
redir "/curl.html" "/x/curl/"
|
||||
redir "/DecSync.html" "/x/DecSync/"
|
||||
redir "/Diseño.html" "/x/Dise%C3%B1o/"
|
||||
redir "/Disroot.html" "/x/Disroot/"
|
||||
redir "/DNS.html" "/x/DNS/"
|
||||
redir "/Donweb.html" "/x/Donweb/"
|
||||
redir "/Dropbear.html" "/x/Dropbear/"
|
||||
redir "/E-ink.html" "/x/E-ink/"
|
||||
redir "/Electronica.html" "/x/Electronica/"
|
||||
redir "/Email.html" "/x/Email/"
|
||||
redir "/EPUB.html" "/x/EPUB/"
|
||||
redir "/Este sitio.html" "/x/Este%20sitio/"
|
||||
redir "/Experiencing harmful behavior in Alpine.html" "/x/Experiencing%20harmful%20behavior%20in%20Alpine/"
|
||||
redir "/Fabricación de circuitos impresos.html" "/x/Fabricaci%C3%B3n%20de%20circuitos%20impresos/"
|
||||
redir "/Facebook.html" "/x/Facebook/"
|
||||
redir "/Faircamp.html" "/x/Faircamp/"
|
||||
redir "/FakeSMTP.html" "/x/FakeSMTP/"
|
||||
redir "/Firecracker.html" "/x/Firecracker/"
|
||||
redir "/Forgejo.html" "/x/Forgejo/"
|
||||
redir "/Formatos de texto.html" "/x/Formatos%20de%20texto/"
|
||||
redir "/Fotografía.html" "/x/Fotograf%C3%ADa/"
|
||||
redir "/Fuck WebRTC.html" "/x/Fuck%20WebRTC/"
|
||||
redir "/Git.html" "/x/Git/"
|
||||
redir "/Gitea.html" "/x/Gitea/"
|
||||
redir "/GNOME.html" "/x/GNOME/"
|
||||
redir "/Go.html" "/x/Go/"
|
||||
redir "/GraphHopper.html" "/x/GraphHopper/"
|
||||
redir "/Hacks: limpiar servidor.html" "/x/Hacks:%20limpiar%20servidor/"
|
||||
redir "/HedgeDoc.html" "/x/HedgeDoc/"
|
||||
redir "/Herramienta de monitoreo de medios.html" "/x/Herramienta%20de%20monitoreo%20de%20medios/"
|
||||
redir "/HTML.html" "/x/HTML/"
|
||||
redir "/Ideas.html" "/x/Ideas/"
|
||||
redir "/Ideas para un sistema operativo propio en Chromebooks.html" "/x/Ideas%20para%20un%20sistema%20operativo%20propio%20en%20Chromebooks/"
|
||||
redir "/Ideas para una web distribuida.html" "/x/Ideas%20para%20una%20web%20distribuida/"
|
||||
redir "/Infraestructura.html" "/x/Infraestructura/"
|
||||
redir "/Internet censurado en escuelas con Plan Sarmiento.html" "/x/Internet%20censurado%20en%20escuelas%20con%20Plan%20Sarmiento/"
|
||||
redir "/Inversiones.html" "/x/Inversiones/"
|
||||
redir "/Jackson Burns - SKIN PURIFYING TREATMENT: Underscore's Melodrama.html" "/x/Jackson%20Burns%20-%20SKIN%20PURIFYING%20TREATMENT:%20Underscore's%20Melodrama/"
|
||||
redir "/Jardin digital.html" "/x/Jardin%20digital/"
|
||||
redir "/JavaScript.html" "/x/JavaScript/"
|
||||
redir "/Javier Milei.html" "/x/Javier%20Milei/"
|
||||
redir "/Keyboard layouts de pocas teclas.html" "/x/Keyboard%20layouts%20de%20pocas%20teclas/"
|
||||
redir "/Leak OSDE 2022-08.html" "/x/Leak%20OSDE%202022-08/"
|
||||
redir "/Lenguajes de marcado.html" "/x/Lenguajes%20de%20marcado/"
|
||||
redir "/Lenguajes de programación.html" "/x/Lenguajes%20de%20programaci%C3%B3n/"
|
||||
redir "/Lua.html" "/x/Lua/"
|
||||
redir "/Lua funcional.html" "/x/Lua/"
|
||||
redir "/Magnets o torrents reproducibles.html" "/x/Magnets%20o%20torrents%20reproducibles/"
|
||||
redir "/Manjaro.html" "/x/Manjaro/"
|
||||
redir "/Markdown.html" "/x/Markdown/"
|
||||
redir "/Marketing.html" "/x/Marketing/"
|
||||
redir "/Measured boot.html" "/x/Measured%20boot/"
|
||||
redir "/Menú artístico.gen.html" "/x/Men%C3%BA%20art%C3%ADstico.gen/"
|
||||
redir "/Mi webring.gen.html" "/"
|
||||
redir "/Multimetro.html" "/x/Multimetro/"
|
||||
redir "/NeoMutt.html" "/x/NeoMutt/"
|
||||
redir "/Nix.html" "/x/Nix/"
|
||||
redir "/Njalla caído.html" "/x/Njalla%20ca%C3%ADdo/"
|
||||
redir "/Not So Shoujo Love Story.html" "/x/Not%20So%20Shoujo%20Love%20Story/"
|
||||
redir "/Nullificación.html" "/bookmarks/2021-12-27-kayak-null/"
|
||||
redir "/Nutrición.html" "/x/Nutrici%C3%B3n/"
|
||||
redir "/Olla a presión.html" "/x/Olla%20a%20presi%C3%B3n/"
|
||||
redir "/OnePlus 5T.html" "/x/OnePlus%205T/"
|
||||
redir "/Opus Encoding.html" "/x/Opus%20Encoding/"
|
||||
redir "/PDF.html" "/x/PDF/"
|
||||
redir "/README.html" "/x/README/"
|
||||
redir "/Salud mental.html" "/x/Salud%20mental/"
|
||||
redir "/Seguridad de la infraestructura de llaves pública (PKI).html" "/x/Seguridad%20de%20la%20infraestructura%20de%20llaves%20p%C3%BAblica%20(PKI)/"
|
||||
redir "/Signal.html" "/x/Signal/"
|
||||
redir "/simplegit.html" "/x/simplegit/"
|
||||
redir "/SONG® Music LLC.html" "/bookmarks/2021-12-17-SONG® Music LLC: NEWSONG® Pro+/"
|
||||
redir "/SQLite.html" "/x/SQLite/"
|
||||
redir "/Subdivx.html" "/x/Subdivx/"
|
||||
redir "/Switches.html" "/x/Switches/"
|
||||
redir "/SyncedStore.html" "/x/SyncedStore/"
|
||||
redir "/Tailwind CSS.html" "/x/CSS/"
|
||||
redir "/Teclados.html" "/x/Teclados/"
|
||||
redir "/Teclados mecánicos.html" "/x/Teclados%20mec%C3%A1nicos/"
|
||||
redir "/Thinkpad X230.html" "/x/Thinkpad%20X230/"
|
||||
redir "/Tipear con una mano.html" "/x/Tipear%20con%20una%20mano/"
|
||||
redir "/To-Do lists.html" "/x/To-Do%20lists/"
|
||||
redir "/Permacomputación.html" "/x/Permacomputaci%C3%B3n/"
|
||||
redir "/Piratería.html" "/x/Pirater%C3%ADa/"
|
||||
redir "/Pleroma.html" "/x/Pleroma/"
|
||||
redir "/Producción de música.html" "/x/Producci%C3%B3n%20de%20m%C3%BAsica/"
|
||||
redir "/Programación.html" "/x/Programaci%C3%B3n/"
|
||||
redir "/ProleText.html" "/x/ProleText/"
|
||||
redir "/Protocolo de toma de decisiones Sutty v0.1.html" "/x/Protocolo%20de%20toma%20de%20decisiones%20Sutty%20v0.1/"
|
||||
redir "/Proyectos.html" "/x/Proyectos/"
|
||||
redir "/PWA.html" "/x/PWA/"
|
||||
redir "/PXE.html" "/x/PXE/"
|
||||
redir "/Python.html" "/x/Python/"
|
||||
redir "/QEMU.html" "/x/QEMU/"
|
||||
redir "/Twitter.html" "/x/Twitter/"
|
||||
redir "/txt2txt.html" "/x/txt2txt/"
|
||||
redir "/underscores - skin purifying treatment.html" "/x/underscores%20-%20skin%20purifying%20treatment/"
|
||||
redir "/underscores - skin purifying treatment b sides.html" "/x/underscores%20-%20skin%20purifying%20treatment%20b%20sides/"
|
||||
redir "/VPS.html" "/x/VPS/"
|
||||
redir "/Web.html" "/x/Web/"
|
||||
redir "/Wikimedia.html" "/x/Wikimedia/"
|
||||
redir "/XMPP.html" "/x/XMPP/"
|
||||
redir "/YouTube.html" "/x/YouTube/"
|
||||
redir "/Quién soy.html" "/x/Qui%C3%A9n%20soy/"
|
||||
redir "/YouTube Restricted Mode.html" "/x/YouTube%20Restricted%20Mode/"
|
||||
}
|
5
Cosas.md
5
Cosas.md
|
@ -1,5 +0,0 @@
|
|||
- [words that cost nothing to scrub from your vocabulary, and maybe you get a tiny sliver of your soul back:<br>
|
||||
content -> art/video/music/comics/games etc, whatever the actual media is<br>
|
||||
consume -> watch/listen/read/play etc<br>
|
||||
IP -> franchise, series, universe, property](https://twitter.com/vectorpoem/status/1575183167497023490)
|
||||
- ![Gráfico si deberías hacer proyecto](Cosas.md-grafico-hacer-proyecto.jpg)
|
|
@ -1,4 +0,0 @@
|
|||
- [luafun/luafun](https://github.com/luafun/luafun) (enfoque en performance dentro de LuaJIT)
|
||||
- [lua-stdlib/functional](https://github.com/lua-stdlib/functional)
|
||||
- [ezerfernandes/funkmoon](https://github.com/ezerfernandes/funkmoon)
|
||||
- [jhoonb/functional-lua](https://github.com/jhoonb/functional-lua)
|
4
Lua.md
4
Lua.md
|
@ -1,4 +0,0 @@
|
|||
- [[Lua funcional]]
|
||||
- [lua-stdlib/lua-stdlib](https://github.com/lua-stdlib/lua-stdlib)
|
||||
- [gvvaughan/typecheck](https://github.com/gvvaughan/typecheck)
|
||||
- [lua-stdlib/strict](https://github.com/lua-stdlib/strict) chequea que hayas definido las variables
|
|
@ -1,3 +0,0 @@
|
|||
- ![Una captura de pantalla de un sitio de pasajes de avión (KAYAK) que dice "Alright! You're off to null." (¡Listo! Ya estás para ir a nulo.)](Nullificación.md-kayak.jpg)
|
||||
|
||||
[twitter.com/RReverser](https://twitter.com/RReverser/status/1466813271000981508)
|
|
@ -1,13 +1,5 @@
|
|||
Este es el README para [el repositorio del sitio](https://gitea.nulo.in/Nulo/sitio).
|
||||
|
||||
## Compilar
|
||||
|
||||
Require [Zig](https://ziglang.org), shell, cmark (con cmark-dev) y Lua 5.1.
|
||||
|
||||
```
|
||||
zig run compilar.zig -lc -lcmark
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
[![Una captura de pantalla de unos mensajes diciendo "pero ponele css nulo, una linea tirate"](pero%20ponele%20css.png)](https://copiona.com)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
- [Pines - An Alpine and Tailwind UI Library](https://devdojo.com/pines)
|
15
_includes/base.hbs
Normal file
15
_includes/base.hbs
Normal file
|
@ -0,0 +1,15 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="author" content="Nulo" />
|
||||
<meta property="og:title" content="{{page.title}}" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content="https://nulo.ar{{{page.url}}}" />
|
||||
<meta property="og:image" content="/cowboy.svg" />
|
||||
<link rel="stylesheet" href="/drip.css" />
|
||||
<link rel="icon" href="/cowboy.svg" />
|
||||
<title>{{page.title}}</title>
|
||||
</head>
|
||||
{{{content}}}
|
||||
</html>
|
19
_includes/bookmark.hbs
Normal file
19
_includes/bookmark.hbs
Normal file
|
@ -0,0 +1,19 @@
|
|||
---
|
||||
layout: base.hbs
|
||||
---
|
||||
<nav>
|
||||
<a href="/">☚ Volver al inicio</a> | En: bookmarks
|
||||
{{> buscador}}
|
||||
</nav>
|
||||
<article itemscope="" itemtype="https://schema.org/Article">
|
||||
<header>
|
||||
<time datetime="{{dateToISO page.date}}" itemprop="datePublished">
|
||||
{{formatDate page.date false}}
|
||||
</time>
|
||||
<h1><a href="{{link}}">{{link}}</a></h1>
|
||||
<h3>{{page.fileSlug}}</h3>
|
||||
</header>
|
||||
<main itemprop="articleBody" data-pagefind-body>
|
||||
{{{content}}}
|
||||
</main>
|
||||
</article>
|
|
@ -1,4 +1,4 @@
|
|||
<script src="_pagefind/pagefind-ui.js" type="text/javascript" defer="defer"></script>
|
||||
<script src="/_pagefind/pagefind-ui.js" type="text/javascript" defer="defer"></script>
|
||||
<div id="search"></div>
|
||||
<script>
|
||||
window.addEventListener("DOMContentLoaded", (event) => {
|
36
_includes/post.hbs
Normal file
36
_includes/post.hbs
Normal file
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
layout: base.hbs
|
||||
---
|
||||
<nav>
|
||||
<a href="/">☚ Volver al inicio</a>
|
||||
{{> buscador}}
|
||||
</nav>
|
||||
<article itemscope="" itemtype="https://schema.org/Article">
|
||||
<header>
|
||||
<h1>{{title}}</h1>
|
||||
{{#unless dateInTitle}}
|
||||
<time datetime="{{dateToISO page.date}}" itemprop="datePublished">
|
||||
{{formatDate page.date false}}
|
||||
</time> /
|
||||
{{/unless}}
|
||||
<a
|
||||
href="https://gitea.nulo.in/Nulo/sitio/commits/branch/ANTIFASCISTA/{{{page.inputPath}}}"
|
||||
>Historial</a>
|
||||
{{#if backlinks.length}}
|
||||
/ <a href="#conexiones">Conexiones</a>
|
||||
{{/if}}
|
||||
</header>
|
||||
<main itemprop="articleBody" data-pagefind-body>
|
||||
{{{content}}}
|
||||
</main>
|
||||
{{#if backlinks.length}}
|
||||
<section id="conexiones">
|
||||
<h2>⥆ Conexiones ({{backlinks.length}})</h2>
|
||||
<ul>
|
||||
{{#each backlinks as |link|}}
|
||||
<li><a href="{{link.url}}">{{link.title}}</a></li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</section>
|
||||
{{/if}}
|
||||
</article>
|
|
@ -1,46 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="aaaaaaaaaaaaaaaaaaaaaaaaaaarainbow.html.css" />
|
||||
<style>
|
||||
body {
|
||||
background: white;
|
||||
color: #111;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
html {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#controls {
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
<title>atr</title>
|
||||
|
||||
<div id="controls">
|
||||
<div class="coso">
|
||||
<label for="rect-width">rect width</label>
|
||||
<input name="rect-width" id="rect-width" type="range" min="2" max="100" />
|
||||
</div>
|
||||
<div class="coso">
|
||||
<label for="rect-height">rect height</label>
|
||||
<input name="rect-height" id="rect-height" type="range" min="2" max="100" />
|
||||
</div>
|
||||
<div class="coso">
|
||||
<label for="diff-x">diff x</label>
|
||||
<input name="diff-x" id="diff-x" type="range" min="-100" max="100" step="0.1" value="10" />
|
||||
</div>
|
||||
<div class="coso">
|
||||
<label for="diff-y">diff y</label>
|
||||
<input name="diff-y" id="diff-y" type="range" min="-100" max="100" step="0.1" value="10" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<canvas></canvas>
|
||||
<script src="aaaaaaaaaaaaaaaaaaaaaaaaaaarainbow.html.js"></script>
|
|
@ -1,49 +0,0 @@
|
|||
// @ts-nocheck
|
||||
const canvas = document.querySelector("canvas");
|
||||
const ctx = canvas.getContext("2d", {
|
||||
alpha: false,
|
||||
});
|
||||
|
||||
function resizeCanvas() {
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
}
|
||||
window.addEventListener("resize", resizeCanvas);
|
||||
resizeCanvas();
|
||||
|
||||
function setupInput(inputId, setFunc) {
|
||||
const input = document.getElementById(inputId);
|
||||
input.addEventListener("input", (event) => {
|
||||
setFunc(parseFloat(event.target.value));
|
||||
});
|
||||
setFunc(parseFloat(input.value));
|
||||
}
|
||||
|
||||
let rect = { width: 50, height: 100 };
|
||||
let diff = { x: 1, y: 1 };
|
||||
|
||||
setupInput("rect-width", (val) => (rect.width = val));
|
||||
setupInput("rect-height", (val) => (rect.height = val));
|
||||
|
||||
setupInput("diff-x", (val) => (diff.x = val));
|
||||
setupInput("diff-y", (val) => (diff.y = val));
|
||||
|
||||
function draw(time) {
|
||||
const i = time / 10;
|
||||
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
const actualDiff = { x: diff.x / rect.width, y: diff.y / rect.height };
|
||||
|
||||
for (let x = 0; x < canvas.width; x += rect.width) {
|
||||
for (let y = 0; y < canvas.height; y += rect.height) {
|
||||
ctx.fillStyle = `hsl(${
|
||||
i + (x / rect.width) * actualDiff.x + (y / rect.height) * actualDiff.y
|
||||
}, 100%, 50%)`;
|
||||
ctx.fillRect(x, y, rect.width, rect.height);
|
||||
}
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(draw);
|
||||
}
|
||||
window.requestAnimationFrame(draw);
|
|
@ -1,3 +1,8 @@
|
|||
---
|
||||
link: "https://newso.ng/musiccypher"
|
||||
tags: diseño
|
||||
---
|
||||
|
||||
SONG® Music LLC. es "un sello discográfico y una plataforma de distriverificacíon con sede en Nueva York, NY". Es una subsidiaria de Parent Company©.<sup>[songm.us][songm.us]</sup>
|
||||
|
||||
[songm.us]: https://songm.us "El sitio de SONG® Music LLC"
|
||||
|
@ -7,7 +12,7 @@ SONG® Music LLC. es "un sello discográfico y una plataforma de distriverificac
|
|||
El sitio para elegir donde escuchar canciones de la discográfica genera opciones exclusivas para desbloquear con "NEWSONG® Pro+".<sup>[newso.ng/musiccypher][newso.ng/musiccypher]</sup>
|
||||
|
||||
<figure>
|
||||
<img alt="Unlock with NEWSONG® Pro+ with three options: Paulstretch this song, Pitch to Zedd and H&M In-Store Playlister" src="SONG® Music LLC.md-NEWSONG_Pro_ejemplo1.png">
|
||||
<img alt="Unlock with NEWSONG® Pro+ with three options: Paulstretch this song, Pitch to Zedd and H&M In-Store Playlister" src="NEWSONG_Pro_ejemplo1.png">
|
||||
<figcaption>
|
||||
|
||||
- "Paulestirar" esta canción ([un método de estirar una canción sin cambiarle el tono](https://manual.audacityteam.org/man/paulstretch.html))
|
||||
|
@ -17,7 +22,7 @@ El sitio para elegir donde escuchar canciones de la discográfica genera opcione
|
|||
</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img alt="Unlock with NEWSONG® Pro+ with five options: Review on RateYourMusic, Rebirth in Correct Generation, Direct-to-CDJ Sync (sponsored), Create TikTok Audio (No Attribution) and thissongissick.com Premiere (sponsored)" src="SONG® Music LLC.md-NEWSONG_Pro_ejemplo2.png">
|
||||
<img alt="Unlock with NEWSONG® Pro+ with five options: Review on RateYourMusic, Rebirth in Correct Generation, Direct-to-CDJ Sync (sponsored), Create TikTok Audio (No Attribution) and thissongissick.com Premiere (sponsored)" src="NEWSONG_Pro_ejemplo2.png">
|
||||
<figcaption>
|
||||
|
||||
- Opinar en RateYourMusic
|
||||
|
@ -29,7 +34,7 @@ El sitio para elegir donde escuchar canciones de la discográfica genera opcione
|
|||
</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img alt="Unlock with NEWSONG® Pro+ with three options: Sync to iPod Nano, AirDrop (Contacts Only) (sponsored) and Generate Type Beat of this audio" src="SONG® Music LLC.md-NEWSONG_Pro_ejemplo3.png">
|
||||
<img alt="Unlock with NEWSONG® Pro+ with three options: Sync to iPod Nano, AirDrop (Contacts Only) (sponsored) and Generate Type Beat of this audio" src="NEWSONG_Pro_ejemplo3.png">
|
||||
<figcaption>
|
||||
|
||||
- Sincronizar a iPod Nano
|
||||
|
@ -39,7 +44,7 @@ El sitio para elegir donde escuchar canciones de la discográfica genera opcione
|
|||
</figcaption>
|
||||
</figure>
|
||||
<figure>
|
||||
<img alt="Unlock with NEWSONG® Pro+ with four options: Request a Masterclass from this artist, Send to Kindle (sponsored), Archive this track on Discogs.com and Guitar Tabs" src="SONG® Music LLC.md-NEWSONG_Pro_ejemplo4.png">
|
||||
<img alt="Unlock with NEWSONG® Pro+ with four options: Request a Masterclass from this artist, Send to Kindle (sponsored), Archive this track on Discogs.com and Guitar Tabs" src="NEWSONG_Pro_ejemplo4.png">
|
||||
<figcaption>
|
||||
|
||||
- Pedir una Masterclass de este artista (Masterclass es una empresa en donde artistas reconocidxs pueden dar clases en línea por precios absurdos)
|
6
bookmarks/2021-12-27-kayak-null/index.md
Normal file
6
bookmarks/2021-12-27-kayak-null/index.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
link: https://twitter.com/RReverser/status/1466813271000981508
|
||||
tags: nullificación
|
||||
---
|
||||
|
||||
![Una captura de pantalla de un sitio de pasajes de avión (KAYAK) que dice "Alright! You're off to null." (¡Listo! Ya estás para ir a nulo.)](kayak.jpg)
|
3
bookmarks/bookmarks.json
Normal file
3
bookmarks/bookmarks.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"layout": "bookmark.hbs"
|
||||
}
|
380
compilar.ts
380
compilar.ts
|
@ -1,380 +0,0 @@
|
|||
import { copyFile, mkdir, opendir, readFile, readdir, writeFile } from "fs/promises";
|
||||
import { basename, extname, join } from "path";
|
||||
import * as commonmark from "commonmark";
|
||||
import {
|
||||
a,
|
||||
h1,
|
||||
header,
|
||||
section,
|
||||
li,
|
||||
link,
|
||||
meta,
|
||||
metaUtf8,
|
||||
render,
|
||||
Renderable,
|
||||
title,
|
||||
ul,
|
||||
h2,
|
||||
raw,
|
||||
VirtualElement,
|
||||
time,
|
||||
article,
|
||||
main,
|
||||
img,
|
||||
nav,
|
||||
} from "@nulo/html.js";
|
||||
|
||||
const reader = new commonmark.Parser({ smart: true });
|
||||
const writer = new commonmark.HtmlRenderer({ safe: false, smart: true });
|
||||
|
||||
const dateFormatter = new Intl.DateTimeFormat("es-AR", {
|
||||
weekday: "long",
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
});
|
||||
|
||||
const wikilinkExp = /\[\[(.+?)\]\]/giu;
|
||||
|
||||
interface Config {
|
||||
sourcePath: string;
|
||||
buildPath: string;
|
||||
}
|
||||
const config: Config = {
|
||||
sourcePath: ".",
|
||||
buildPath: "build",
|
||||
};
|
||||
|
||||
const buscadorHtml = await readFile("buscador.htm", "utf-8");
|
||||
|
||||
const connections = await scanForConnections(config.sourcePath);
|
||||
|
||||
await mkdir(config.buildPath, { recursive: true });
|
||||
|
||||
const dir = await readdir(config.sourcePath, { withFileTypes: true });
|
||||
let pageList: { src: string }[] = [];
|
||||
for (const entry of dir) {
|
||||
if (!entry.isFile()) continue;
|
||||
const { name } = entry;
|
||||
const extension = extname(name);
|
||||
|
||||
if ([".ts", ".md", ".css", ".js", ".png", ".jpg", ".mp4", ".svg", ".html"].includes(extension)) {
|
||||
await copyFile(join(config.sourcePath, name), join(config.buildPath, name));
|
||||
}
|
||||
|
||||
if ([".md"].includes(extension) || name.endsWith(".gen.js")) {
|
||||
pageList.push({ src: name });
|
||||
}
|
||||
}
|
||||
await Promise.all(pageList.map(({ src }) => compilePage(config, src)));
|
||||
|
||||
await compilePageList(config, pageList);
|
||||
|
||||
async function compileFile(
|
||||
config: Config,
|
||||
sourceFileName: string,
|
||||
): Promise<{ contentHtml: string; image?: Image }> {
|
||||
if (extname(sourceFileName) === ".md") {
|
||||
const { html: contentHtml, image } = await compileMarkdownHtml(config, sourceFileName);
|
||||
return { contentHtml, image };
|
||||
} else if (sourceFileName.endsWith(".gen.js")) {
|
||||
const contentHtml = await compileJavascript(config, sourceFileName);
|
||||
return { contentHtml };
|
||||
} else if (sourceFileName.endsWith(".htm"))
|
||||
return { contentHtml: await readFile(sourceFileName, "utf-8") };
|
||||
else throw false;
|
||||
}
|
||||
|
||||
async function compilePage(config: Config, sourceFileName: string) {
|
||||
const name = basename(sourceFileName, extname(sourceFileName));
|
||||
const isIndex = name === "index";
|
||||
const title = isIndex ? "nulo.ar" : formatNameToPlainText(name);
|
||||
const fileConnections = connections.filter(({ linked }) => linked === name);
|
||||
|
||||
const { contentHtml, image } = await compileFile(config, sourceFileName);
|
||||
|
||||
const html = renderHtml(
|
||||
...generateHead(title, name),
|
||||
article(
|
||||
{ itemscope: "", itemtype: "https://schema.org/Article" },
|
||||
...(isIndex ? [] : generateHeader(name, sourceFileName, fileConnections.length > 0, image)),
|
||||
main({ itemprop: "articleBody", "data-pagefind-body": "" }, raw(contentHtml)),
|
||||
...generateConnectionsSection(fileConnections),
|
||||
),
|
||||
);
|
||||
|
||||
const outputPath = join(config.buildPath, name + ".html");
|
||||
await writeFile(outputPath, html);
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Get HTML
|
||||
// ==============================================
|
||||
|
||||
type Image = {
|
||||
src: string;
|
||||
alt: string;
|
||||
};
|
||||
|
||||
async function compileMarkdownHtml(
|
||||
config: Config,
|
||||
sourceFileName: string,
|
||||
): Promise<{ html: string; image?: Image }> {
|
||||
let markdown = await readFile(join(config.sourcePath, sourceFileName), "utf-8");
|
||||
|
||||
let image;
|
||||
if (markdown.startsWith("!!")) {
|
||||
const node = reader.parse(markdown.slice(1, markdown.indexOf("\n")));
|
||||
const imageNode = node.firstChild?.firstChild;
|
||||
if (!imageNode || !imageNode.destination)
|
||||
throw new Error("Intenté parsear un ^!! pero no era una imágen");
|
||||
if (!imageNode.firstChild?.literal) console.warn(`El ^!! de ${sourceFileName} no tiene alt`);
|
||||
|
||||
image = {
|
||||
src: imageNode.destination,
|
||||
alt: imageNode.firstChild?.literal || "",
|
||||
};
|
||||
markdown = markdown.slice(markdown.indexOf("\n"));
|
||||
}
|
||||
|
||||
const parsed = reader.parse(markdown);
|
||||
const markdownHtml = writer.render(parsed);
|
||||
|
||||
checkLinks(sourceFileName, markdownHtml);
|
||||
const contentHtml = await hackilyTransformHtml(markdownHtml);
|
||||
return { html: contentHtml, image };
|
||||
}
|
||||
|
||||
async function compileJavascript(config: Config, sourceFileName: string): Promise<string> {
|
||||
const fn = await import("./" + join(config.sourcePath, sourceFileName));
|
||||
return await fn.default();
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Generated HTML
|
||||
// ==============================================
|
||||
|
||||
function renderHtml(...world: Renderable[]): string {
|
||||
return `<!doctype html><html lang="es">` + render(...world) + "</html>";
|
||||
}
|
||||
|
||||
function generateHead(titlee: string, outputName: string): Renderable[] {
|
||||
// TODO: deshardcodear og:url
|
||||
return [
|
||||
metaUtf8,
|
||||
meta({
|
||||
name: "viewport",
|
||||
content: "width=device-width, initial-scale=1.0",
|
||||
}),
|
||||
meta({ name: "author", content: "Nulo" }),
|
||||
meta({ property: "og:title", content: titlee }),
|
||||
meta({ property: "og:type", content: "website" }),
|
||||
meta({ property: "og:url", content: `https://nulo.ar/${outputName}.html` }),
|
||||
meta({ property: "og:image", content: "cowboy.svg" }),
|
||||
link({ rel: "stylesheet", href: "drip.css" }),
|
||||
link({ rel: "icon", href: "cowboy.svg" }),
|
||||
title(titlee),
|
||||
];
|
||||
}
|
||||
|
||||
function formatDate(dateish: Dateish, upper: boolean = false): string {
|
||||
const date = new Date(dateish.year, dateish.month - 1, dateish.day);
|
||||
const formatted = dateFormatter.format(date);
|
||||
if (upper) {
|
||||
// no le digan a la policía del unicode!
|
||||
return formatted[0].toUpperCase() + formatted.slice(1);
|
||||
} else return formatted;
|
||||
}
|
||||
|
||||
interface Dateish {
|
||||
year: number;
|
||||
month: number;
|
||||
day: number;
|
||||
}
|
||||
function dateishToString({ year, month, day }: Dateish): string {
|
||||
return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
type TitleMetadata =
|
||||
| {
|
||||
// title puede tener length == 0 y por lo tanto ser falseish
|
||||
title: string;
|
||||
date?: Dateish;
|
||||
}
|
||||
| { date: Dateish };
|
||||
function parseName(name: string): TitleMetadata {
|
||||
const titleWithDate = /^((?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2}))? ?(?<title>.*)$/;
|
||||
|
||||
const found = name.match(titleWithDate);
|
||||
if (!found || !found.groups) throw new Error("Algo raro pasó");
|
||||
const { title } = found.groups;
|
||||
|
||||
const date =
|
||||
(found.groups.year && {
|
||||
year: parseInt(found.groups.year),
|
||||
month: parseInt(found.groups.month),
|
||||
day: parseInt(found.groups.day),
|
||||
}) ||
|
||||
undefined;
|
||||
// no definir title si es length == 0
|
||||
if (!title && date) return { date };
|
||||
return { title, date };
|
||||
}
|
||||
|
||||
function dateishToElement(
|
||||
dateish: Dateish,
|
||||
{ itemprop, upper }: { itemprop?: string; upper?: boolean } = {},
|
||||
): VirtualElement {
|
||||
return time(
|
||||
{ datetime: dateishToString(dateish), ...(itemprop ? { itemprop } : {}) },
|
||||
formatDate(dateish, upper),
|
||||
);
|
||||
}
|
||||
|
||||
function formatNameToInline(name: string): Renderable[] {
|
||||
const parsed = parseName(name);
|
||||
if ("title" in parsed) {
|
||||
const { title, date } = parsed;
|
||||
return [title, ...(date ? [` (`, dateishToElement(date), `)`] : [])];
|
||||
} else {
|
||||
return [dateishToElement(parsed.date, { upper: true })];
|
||||
}
|
||||
}
|
||||
function formatNameToPlainText(name: string): string {
|
||||
const parsed = parseName(name);
|
||||
if ("title" in parsed) {
|
||||
const { title, date } = parsed;
|
||||
return title + (date ? ` (${formatDate(date)})` : "");
|
||||
} else {
|
||||
return formatDate(parsed.date, true);
|
||||
}
|
||||
}
|
||||
|
||||
function generateHeader(
|
||||
name: string,
|
||||
sourceCodePath: string,
|
||||
linkConexiones = false,
|
||||
image?: Image,
|
||||
): Renderable[] {
|
||||
const parsedTitle = parseName(name);
|
||||
return [
|
||||
nav(a({ href: "." }, "☚ Volver al inicio"), raw(buscadorHtml)),
|
||||
header(
|
||||
...(image ? [img({ ...image, itemprop: "image" })] : []),
|
||||
...("title" in parsedTitle
|
||||
? [
|
||||
h1(parsedTitle.title),
|
||||
...(parsedTitle.date
|
||||
? [
|
||||
dateishToElement(parsedTitle.date, {
|
||||
itemprop: "datePublished",
|
||||
}),
|
||||
" / ",
|
||||
]
|
||||
: []),
|
||||
]
|
||||
: [
|
||||
h1(
|
||||
dateishToElement(parsedTitle.date, {
|
||||
itemprop: "datePublished",
|
||||
upper: true,
|
||||
}),
|
||||
),
|
||||
]),
|
||||
a(
|
||||
{
|
||||
href: `https://gitea.nulo.in/Nulo/sitio/commits/branch/ANTIFASCISTA/${sourceCodePath}`,
|
||||
},
|
||||
"Historial",
|
||||
),
|
||||
...(linkConexiones ? [" / ", a({ href: "#conexiones" }, "Conexiones")] : []),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
function generateConnectionsSection(fileConnections: Connection[]): Renderable[] {
|
||||
return fileConnections.length > 0
|
||||
? [
|
||||
section(
|
||||
{ id: "conexiones" },
|
||||
h2(`⥆ Conexiones (${fileConnections.length})`),
|
||||
ul(...fileConnections.map(({ linker }) => li(internalLink(linker)))),
|
||||
),
|
||||
]
|
||||
: [];
|
||||
}
|
||||
|
||||
async function compilePageList(config: Config, pageList: { src: string }[]) {
|
||||
const name = "Lista de páginas";
|
||||
const outputPath = join(config.buildPath, name + ".html");
|
||||
const html = renderHtml(
|
||||
...generateHead(name, name),
|
||||
...generateHeader(name, "compilar.ts"),
|
||||
ul(
|
||||
...pageList
|
||||
.map(({ src: name }) => basename(name, extname(name)))
|
||||
.sort((a, b) => a.localeCompare(b, "es", { sensitivity: "base" }))
|
||||
.map((name) => li(internalLink(name))),
|
||||
),
|
||||
);
|
||||
await writeFile(outputPath, html);
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Conexiones
|
||||
// ==============================================
|
||||
|
||||
interface Connection {
|
||||
linked: string;
|
||||
linker: string;
|
||||
}
|
||||
|
||||
async function scanForConnections(sourcePath: string): Promise<Connection[]> {
|
||||
const dir = await opendir(sourcePath);
|
||||
let connections: Connection[] = [];
|
||||
for await (const entry of dir) {
|
||||
const extension = extname(entry.name);
|
||||
if (extension === ".md") {
|
||||
const name = basename(entry.name, ".md");
|
||||
const file = await readFile(join(config.sourcePath, entry.name), "utf-8");
|
||||
for (const [, linked] of file.matchAll(wikilinkExp)) {
|
||||
connections.push({ linked, linker: name });
|
||||
}
|
||||
}
|
||||
}
|
||||
return connections;
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Markdown utils
|
||||
// ==============================================
|
||||
|
||||
async function hackilyTransformHtml(html: string): Promise<string> {
|
||||
html = html
|
||||
.replaceAll("<a h", '<a rel="noopener noreferrer" h')
|
||||
.replaceAll(wikilinkExp, (_, l) => render(internalLink(l)));
|
||||
for (const [match, archivo] of html.matchAll(/<nulo-sitio-reemplazar-con archivo="(.+?)" \/>/g)) {
|
||||
html = html.replace(match, (await compileFile(config, archivo)).contentHtml);
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
function checkLinks(srcName: string, html: string) {
|
||||
const matches = html.matchAll(wikilinkExp);
|
||||
const list = pageList.map(({ src }) => basename(src, extname(src)));
|
||||
if (!matches) return;
|
||||
for (const match of matches) {
|
||||
if (!list.some((n) => n === match[1])) {
|
||||
console.warn(`${srcName} linkea a ${match[1]}, pero no existe`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==============================================
|
||||
// Linking
|
||||
// ==============================================
|
||||
|
||||
function internalLink(path: string): VirtualElement {
|
||||
const href = encodeURI(`./${path}.html`);
|
||||
return a({ href }, ...formatNameToInline(path));
|
||||
}
|
3
drip.css
3
drip.css
|
@ -93,3 +93,6 @@ li {
|
|||
padding: 1rem;
|
||||
border: 1px solid;
|
||||
}
|
||||
#search form {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
14
feeds.js
14
feeds.js
|
@ -1,7 +1,7 @@
|
|||
import { readFile, writeFile } from "fs/promises";
|
||||
import { join } from "path";
|
||||
const { readFile, writeFile } = require("fs/promises");
|
||||
const { join } = require("path");
|
||||
|
||||
export const feeds = {
|
||||
const feeds = {
|
||||
fauno: "https://fauno.endefensadelsl.org/feed.xml",
|
||||
copiona: "https://copiona.com/feed.xml",
|
||||
j3s: "https://j3s.sh/feed.atom",
|
||||
|
@ -11,14 +11,16 @@ export const feeds = {
|
|||
};
|
||||
|
||||
if (process.argv[2] === "refresh") {
|
||||
(async () => {
|
||||
await Promise.all(
|
||||
Object.entries(feeds).map(async ([name, url]) => {
|
||||
console.log(`Refreshing ${name}`);
|
||||
const res = await fetch(url);
|
||||
const txt = await res.text();
|
||||
await writeFile(join("cached-feeds/", `${name}.xml`), txt);
|
||||
}),
|
||||
})
|
||||
);
|
||||
})();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,6 +28,8 @@ if (process.argv[2] === "refresh") {
|
|||
* @param {string} name
|
||||
* @returns string
|
||||
*/
|
||||
export async function readFeed(name) {
|
||||
async function readFeed(name) {
|
||||
return await readFile(join("cached-feeds/", name + ".xml"), "utf-8");
|
||||
}
|
||||
|
||||
module.exports = { feeds, readFeed };
|
||||
|
|
65
helpers/date.js
Normal file
65
helpers/date.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
const z = require("zod");
|
||||
|
||||
const dateishExp = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/;
|
||||
const zDateish = z
|
||||
.string()
|
||||
.regex(dateishExp)
|
||||
.transform((s) => {
|
||||
const found = s.match(dateishExp);
|
||||
return {
|
||||
year: parseInt(found.groups.year),
|
||||
month: parseInt(found.groups.month),
|
||||
day: parseInt(found.groups.day),
|
||||
};
|
||||
});
|
||||
/** @typedef {z.infer<zDateish>} Dateish */
|
||||
|
||||
const dateFormatter = new Intl.DateTimeFormat("es-AR", {
|
||||
weekday: "long",
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
timeZone: "UTC",
|
||||
});
|
||||
/**
|
||||
* @param {Dateish} dateish
|
||||
* @returns Date
|
||||
*/
|
||||
function dateishToDate(dateish) {
|
||||
return new Date(dateish.year, dateish.month - 1, dateish.day);
|
||||
}
|
||||
/**
|
||||
* @param {Date} date
|
||||
* @param {boolean} upper
|
||||
* @returns string
|
||||
*/
|
||||
function formatDate(date, upper = false) {
|
||||
const formatted = dateFormatter.format(date);
|
||||
if (upper) {
|
||||
// no le digan a la policía del unicode!
|
||||
return formatted[0].toUpperCase() + formatted.slice(1);
|
||||
} else return formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Dateish} dateis
|
||||
* @returns string
|
||||
*/
|
||||
function dateishToString({ year, month, day }) {
|
||||
return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @param {Dateish} dateish
|
||||
// * @param {{ itemprop?: string, upper?: boolean }} params
|
||||
// * @returns string
|
||||
// */
|
||||
// function dateishToElement(dateish, { itemprop, upper } = {}) {
|
||||
// const itempropParam = (itemprop && ` itemprop="${itemprop}"`) || "";
|
||||
// return `<time datetime="${dateishToString(dateish)}" ${itempropParam}>${formatDate(
|
||||
// dateishToDate(dateish),
|
||||
// upper
|
||||
// )}</time>`;
|
||||
// }
|
||||
|
||||
module.exports = { formatDate, zDateish, dateishToDate };
|
|
@ -1,43 +1,19 @@
|
|||
import path from "node:path";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import { parseFeed as _parseFeed } from "htmlparser2";
|
||||
import { a, li, raw, render, ul } from "@nulo/html.js";
|
||||
import { parseDocument } from "htmlparser2";
|
||||
import { getElementsByTagName } from "domutils";
|
||||
import { feeds, readFeed } from "./feeds.js";
|
||||
const { parseFeed: _parseFeed } = require("htmlparser2");
|
||||
const { parseDocument } = require("htmlparser2");
|
||||
const { getElementsByTagName } = require("domutils");
|
||||
const { feeds, readFeed } = require("./feeds.js");
|
||||
|
||||
export default async () => {
|
||||
module.exports = async () => {
|
||||
const articles = [];
|
||||
|
||||
for (const [name, baseUrl] of Object.entries(feeds)) {
|
||||
/**
|
||||
* @param {string} link
|
||||
* @returns string
|
||||
*/
|
||||
const relativeLink = (link) => new URL(link, baseUrl).toString();
|
||||
|
||||
const rawFeed = await readFeed(name);
|
||||
const { title, item, link } = parseFeed(baseUrl, rawFeed);
|
||||
|
||||
articles.push(
|
||||
li(
|
||||
{ class: "article" },
|
||||
a(
|
||||
{
|
||||
href: relativeLink(item.link),
|
||||
target: "_blank",
|
||||
rel: "noopener",
|
||||
},
|
||||
item.title,
|
||||
),
|
||||
// TODO: format date
|
||||
" via ",
|
||||
a({ href: relativeLink(link), rel: "noopener" }, title),
|
||||
),
|
||||
);
|
||||
articles.push({ title, item, link, baseUrl });
|
||||
}
|
||||
|
||||
return render(ul(...articles));
|
||||
return { articles };
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -53,19 +29,19 @@ function parseFeed(feedUrl, rawFeed) {
|
|||
const feedDom = getElementsByTagName(
|
||||
(n) => n === "rss" || n === "feed" || n === "rdf:RDF",
|
||||
dom.childNodes,
|
||||
false,
|
||||
false
|
||||
)[0];
|
||||
const linksDom = getElementsByTagName(
|
||||
(t) => ["link", "atom:link"].includes(t),
|
||||
feedDom.childNodes,
|
||||
false,
|
||||
false
|
||||
);
|
||||
const linkDom = linksDom.find(
|
||||
(d) =>
|
||||
d.attribs.rel === "alternate" ||
|
||||
// https://datatracker.ietf.org/doc/html/rfc4287#section-4.2.7.2
|
||||
// >If the "rel" attribute is not present, the link element MUST be interpreted as if the link relation type is "alternate".
|
||||
!("rel" in d.attribs),
|
||||
!("rel" in d.attribs)
|
||||
);
|
||||
|
||||
const feedUrll = new URL(feedUrl);
|
33
index.md
33
index.md
|
@ -1,19 +1,24 @@
|
|||
---
|
||||
layout: base.hbs
|
||||
templateEngineOverride: hbs,md
|
||||
---
|
||||
|
||||
<h1 class="main-title">nulo❥ar</h1>
|
||||
|
||||
> What's bizarre? I mean, we're all pretty bizarre.<br>Some of us are just better at hiding it, that's all.
|
||||
|
||||
<nulo-sitio-reemplazar-con archivo="buscador.htm" />
|
||||
{{> buscador}}
|
||||
|
||||
¡Buenas! Este es mi mundo, bienvenidx. ¿Que, [[Quién soy]]? Soy Nulo :)
|
||||
¡Buenas! Este es mi mundo, bienvenidx. ¿Que, [[/x/Quién soy]]? Soy Nulo :)
|
||||
|
||||
- Perdete en la [[Lista de páginas]]
|
||||
- Perdete en la [[/x/Lista de páginas]]
|
||||
|
||||
Algunas cosas que escribí:
|
||||
|
||||
- [[2023-04-30 Donweb quiere tu cripto]]
|
||||
- [[2023-02-05 Vergüenza algorítmica]]
|
||||
- [[2022-10-15 Analisis de la extracción de datos del teléfono de Fernando André Sabag Montiel]]
|
||||
- [[Arreglando bugs ajenos]]
|
||||
- [[/x/2023-04-30-Donweb quiere tu cripto]]
|
||||
- [[/x/2023-02-05-Vergüenza algorítmica]]
|
||||
- [[/x/2022-10-15-Analisis de la extracción de datos del teléfono de Fernando André Sabag Montiel]]
|
||||
- [[/x/2021-10-11-Arreglando bugs ajenos]]
|
||||
|
||||
Algunas cosas que hice:
|
||||
|
||||
|
@ -24,7 +29,7 @@ Algunas cosas que hice:
|
|||
- [Schreiben](https://beta.schreiben.nulo.ar): una aplicación para escribir cosas ([código](https://gitea.nulo.in/Nulo/schreiben))
|
||||
- Laburos:
|
||||
- [Salvá la costanera](https://salva-la-costanera.netlify.app/), [código](https://gitea.nulo.in/Nulo/salva-la-costanera)
|
||||
- Y otros [[Proyectos]].
|
||||
- Y otros [[/x/Proyectos]].
|
||||
|
||||
Algunas cosas de las que soy parte:
|
||||
|
||||
|
@ -35,9 +40,17 @@ Algunos links mios:
|
|||
- <a rel="me noopener noreferrer" href="https://todon.eu/@Nulo">Mastodon</a>
|
||||
- Mis [repositorios de código en Gitea](https://gitea.nulo.in/Nulo) y en [GitHub](https://github.com/catdevnull)
|
||||
|
||||
## Feed de personas que me parecen copadas ([[Mi webring.gen]])
|
||||
## Feed de personas que me parecen copadas (un webring)
|
||||
|
||||
<nulo-sitio-reemplazar-con archivo="Mi webring.gen.js" />
|
||||
<ul>
|
||||
{{#each articles as |article|}}
|
||||
<li class="article">
|
||||
<a href="{{relativeLink article.item.link article.baseUrl}}" target="_blank" rel="noopener">{{article.item.title}}</a>
|
||||
via
|
||||
<a href="{{article.link}}">{{article.title}}</a>
|
||||
</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
## Contacto
|
||||
|
||||
|
|
18
package.json
18
package.json
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"name": "sitio",
|
||||
"type": "module",
|
||||
"//type": "module",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "esbuild compilar.ts *.js --target=node18 --outdir=build-js --sourcemap && node --enable-source-maps --trace-uncaught build-js/compilar.js && pagefind --source build",
|
||||
"build-bun": "bun build compilar.ts --target bun > build-js/bun.js && bun build-js/bun.js && pagefind --source build",
|
||||
"pagefind": "pagefind --source build",
|
||||
"build": "eleventy && pnpm pagefind",
|
||||
"watch": "eleventy --watch",
|
||||
"check": "tsc",
|
||||
"refresh-feeds": "node feeds.js refresh"
|
||||
},
|
||||
|
@ -14,16 +15,17 @@
|
|||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@11ty/eleventy": "^2.0.1",
|
||||
"@types/commonmark": "^0.27.5",
|
||||
"@types/node": "^18.11.18",
|
||||
"esbuild": "^0.16.17",
|
||||
"typescript": "^4.9.4"
|
||||
"typescript": "^5.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nulo/html.js": "^0.0.8",
|
||||
"commonmark": "^0.30.0",
|
||||
"domutils": "^3.0.1",
|
||||
"eleventy-plugin-automatic-noopener": "^2.0.2",
|
||||
"htmlparser2": "^8.0.2",
|
||||
"pagefind": "^0.12.0"
|
||||
"markdown-it-wikilinks": "^1.4.0",
|
||||
"pagefind": "^0.12.0",
|
||||
"zod": "^3.22.4"
|
||||
}
|
||||
}
|
||||
|
|
1485
pnpm-lock.yaml
1485
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
1
status/404.md
Normal file
1
status/404.md
Normal file
|
@ -0,0 +1 @@
|
|||
No encontré esta página... [Volver al hogar](/)
|
36
timer.html
36
timer.html
|
@ -1,36 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="https://nulo.in/drip.css" />
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
}
|
||||
main {
|
||||
text-align: center;
|
||||
padding: 0 1em;
|
||||
}
|
||||
input {
|
||||
width: 5em;
|
||||
}
|
||||
</style>
|
||||
<title>Timer de guita</title>
|
||||
|
||||
<main>
|
||||
<h1>Guita: <span id="guita" data-guita="0">$ 0.00</span></h1>
|
||||
<div>
|
||||
<label for="por-hora">Guita por hora por persona:</label>
|
||||
<input value="0" type="number" id="por-hora" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="personas">Cantidad de personas:</label>
|
||||
<input value="1" type="number" id="personas" />
|
||||
</div>
|
||||
<button>Empezar</button>
|
||||
</main>
|
||||
|
||||
<script src="timer.html.js"></script>
|
|
@ -1,21 +0,0 @@
|
|||
// @ts-nocheck
|
||||
const guitaEl = document.querySelector("#guita");
|
||||
const porHoraEl = document.querySelector("#por-hora");
|
||||
const personasEl = document.querySelector("#personas");
|
||||
const buttonEl = document.querySelector("button");
|
||||
|
||||
let interval = null;
|
||||
|
||||
buttonEl.addEventListener("click", (event) => {
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
buttonEl.textContent = "Empezar";
|
||||
} else {
|
||||
interval = setInterval(() => {
|
||||
guitaEl.dataset.guita =
|
||||
parseFloat(guitaEl.dataset.guita) + (porHoraEl.value / 60 / 60) * personasEl.value;
|
||||
guitaEl.textContent = `$ ${parseFloat(guitaEl.dataset.guita).toFixed(2)}`;
|
||||
}, 1000);
|
||||
buttonEl.textContent = "Parar";
|
||||
}
|
||||
});
|
|
@ -8,6 +8,9 @@
|
|||
"strict": true,
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"noEmit": true
|
||||
"noEmit": true,
|
||||
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ Por un tiempo, tuve una de mis muñecas inaccesibles por unas semanas. Esto me o
|
|||
|
||||
Recientemente, en el sitio agregaron una solapa de "transcripción" mostrando todo el dialogo que había en el video del ejercicio. Sin embargo, cuando esta solapa estaba cerrada, se podían seguir seleccionando los enlaces dentro de la solapa con el teclado, haciendo la navegación por teclado tediosa.
|
||||
|
||||
<video controls src="Arreglando bugs ajenos.md-details.mp4">Tu navegador no soporta video HTML5.</video>
|
||||
<video controls src="details.mp4">Tu navegador no soporta video HTML5.</video>
|
||||
|
||||
La solucion es simplemente usar el elemento de solapa que ya viene con el navegador: [`<details>`](https://developer.mozilla.org/es/docs/Web/HTML/Element/details). (La página de `<details>` en MDN esta desactualizada al momento de escribir este artículo.)
|
||||
|
40
x/2022-11-18-Donweb es ridículo.md
Normal file
40
x/2022-11-18-Donweb es ridículo.md
Normal file
|
@ -0,0 +1,40 @@
|
|||
_[Parte 2](/x/2023-04-30-Donweb%20quiere%20tu%20cripto/)_
|
||||
|
||||
Hace unos días compre el "Cloud Server" (VPS) más barato que ofrece [[Donweb]] para experimentar ya que no había visto hosting en Argentina tan barato antes. No ofrecían la posibilidad de bootear distros alternativas a las que te ofrecen (Debian, Ubuntu, CentOS y Rocky) que me pareció raro, pero todo se puede hackear.
|
||||
|
||||
Me pareció raro/sospechoso que la instalación de Debian por defecto venía con las llaves SSH de muchisimxs empleadxs de Donweb en el authorized_keys de root dandoles acceso de superusuario, por lo que las borré.
|
||||
|
||||
Bootié una imágen de otro de mis proyectos experimentales, [define-alpine](https://gitea.nulo.in/Nulo/define-alpine), ya que quería ver que tan complicado era hacerlo funcionar en un entorno poco flexible como este. Por las 23 horas, lo logré, mandando esta captura de pantalla de victoria a un amigo:
|
||||
|
||||
![Captura de pantalla de una terminal de Linux con una sesión recién iniciada](captura-pre.jpg)
|
||||
|
||||
Me fui a dormir victorioso. Al día siguiente, por las 10 de la mañana, recibo este mail:
|
||||
|
||||
> Buenos días! como estas? espero que te encuentres muy bien! Tomo contacto contigo en esta ocasión para informarte que deberás re-crear el cloud correspondiente ya que has Instalado otro SO arriba de la imagen provista y no esta permitido.
|
||||
>
|
||||
> Saludos cordiales,
|
||||
>
|
||||
> Quedo a tu disposición y te agradezco califiques mi respuesta porque nos ayudará a mejorar la calidad de atención.
|
||||
>
|
||||
> <pre>---------------------------------------------</pre><br>
|
||||
>
|
||||
> [CENSURADO]<br>
|
||||
> Cloud & IaaS Technical Support - Donweb.cloud<br>
|
||||
>
|
||||
> <pre>---------------------------------------------</pre>
|
||||
|
||||
En ese momento estaba encerrado en una institución educativa, pero mi amigo descubrió que efectivamente sus terminos y condiciones lo prohibian entre otras cosas.
|
||||
|
||||
> Se incluye en este punto también cualquier otra información que DonWeb by Dattatec considere inapropiada según su absoluto y exclusivo criterio. Cualquier uso indebido de los servicios autorizará a DonWeb by Dattatec a la suspensión o eliminación de los servicios contratados y sus contenidos sin previo aviso, no haciéndose responsable DonWeb by Dattatec por cualquier pérdida que esto implique.
|
||||
|
||||
> El servidor deberá responder a SNMP (http://es.wikipedia.org/wiki/Simple_Network_Management_Protocol) desde ciertas IPs utilizadas por DonWeb by Dattatec para monitoreo del servicio las cuales son asignadas en la configuracion al momento del alta. El cliente no deberá desinstalar el servicio SNMP ni modificar su configuracion.
|
||||
|
||||
> DonWeb by Dattatec se reserva el derecho de suspender el servicio en cualquier momento en caso de detectar alguna anormalidad en las configuraciones antes mencionadas y no poder acceder al servidor para realizar las correcciones necesarias.
|
||||
|
||||
> IMPORTANTE: Una vez adquirido el Cloud Server, el cliente tiene la posibilidad de instalar cualquier imagen de los SO ofrecidos que se ajuste a sus necesidades. No obstante, el cliente debe abstenerse de instalar (o pisar una instalación) con una distribución y/o Sistema Operativo distinto a los ofrecidos en el catálogo de imágenes de DonWeb. DonWeb se reserva el derecho de suspender sin previo aviso el servicio en caso que se detecte lo antes mencionado o cualquier acción que comprometa la seguridad e integridad del servicio o la compañía.
|
||||
|
||||
DonYuta o RatiWeb, bue. Cuando logre escapar de dicha institución educativa y llegué a mi computador portable, descubrí que Donweb se había tomado la libertad de entrar al VNC de mi servidor a clavarse unos comandos:
|
||||
|
||||
![Captura de pantalla de una terminal de Linux con varios comandos consultando información sobre el sistema operativo que corría, entre otras cosas](captura-post.jpg)
|
||||
|
||||
No recomiendo.
|
|
@ -1,10 +1,10 @@
|
|||
_[Parte 1](2022-11-18%20Donweb%20es%20rid%C3%ADculo.html)_
|
||||
_[Parte 1](/x/2022-11-18-Donweb%20es%20rid%C3%ADculo/)_
|
||||
|
||||
Como si no fuera suficiente, [[Donweb]] me sigue mandando mails por más que me desuscribí varias veces. No debería sorprenderme de la empresa que hace _[Email Marketing](https://envialosimple.com/es-ar)_ (Spam as a Service), pero es hinchapelotas.
|
||||
|
||||
Ayer recibí un mail un poco raro.
|
||||
|
||||
![un email que proveniente de Donweb pero con el nombre de enviador como "metamask" alertandome de que supuestamente el acceso a mi cripto habría sido suspendido](2023-04-30%20Donweb%20quiere%20tu%20cripto.md-Screenshot%20from%202023-04-30%2016-28-20.png)
|
||||
![un email que proveniente de Donweb pero con el nombre de enviador como "metamask" alertandome de que supuestamente el acceso a mi cripto habría sido suspendido](screenshot-mail.png)
|
||||
|
||||
Al principió quise asumir que quizás Doncopado decidió notificarnos de algo que afectaba a MetaMask en general, aunque realmente sospechaba que era una estafa.
|
||||
|
3
x/Atreus v1.md
Normal file
3
x/Atreus v1.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
![Foto del Atreus v1 de frente](frente.jpg)
|
||||
|
||||
![Foto del Atreus v1 de atrás, exponiendo sus cables interiores](atrás.jpg)
|
|
@ -1,6 +1,6 @@
|
|||
Término técnico para esta receta. [Viene de TikTok](https://www.tiktok.com/@foodiechina888/video/7071812170157198594). TRENDING **TOFU** RECIPE IN CHINA.
|
||||
|
||||
<video src="CHINESE GOD OIL.md-tiktok.h264.mp4" controls></video>
|
||||
<video src="tiktok.h264.mp4" controls></video>
|
||||
|
||||
1. - Harina de almidón de maíz (maicena) (la receta pide "potato starch" pero YOLO)
|
||||
- Huevos revueltos (sin cocinar lol)
|
14
x/CSS/index.md
Normal file
14
x/CSS/index.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
## Tailwind
|
||||
|
||||
El mejor framework del mundo.
|
||||
|
||||
- [Pines - An Alpine and Tailwind UI Library](https://devdojo.com/pines)
|
||||
|
||||
## color-scheme ([MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme))
|
||||
|
||||
Es una propiedad de CSS que indica en que colores se puede renderizar tu sitio. Si especificas `color-scheme: dark`, los navegadores automáticamente cambian los colores del fondo, el texto, los inputs, etc para ajustarse a eso. Sin embargo, Safari elije colores pésimos:
|
||||
|
||||
<figure>
|
||||
<img src="color-scheme-safari-nulo.ar.jpg" />
|
||||
<figcaption>nulo.ar antes de que especifique colores para los links</figcaption>
|
||||
</figure>
|
5
x/Cosas.md
Normal file
5
x/Cosas.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
- [words that cost nothing to scrub from your vocabulary, and maybe you get a tiny sliver of your soul back:<br>
|
||||
content -> art/video/music/comics/games etc, whatever the actual media is<br>
|
||||
consume -> watch/listen/read/play etc<br>
|
||||
IP -> franchise, series, universe, property](https://twitter.com/vectorpoem/status/1575183167497023490)
|
||||
- ![Gráfico si deberías hacer proyecto](grafico-hacer-proyecto.jpg)
|
Some files were not shown because too many files have changed in this diff Show more
Reference in a new issue