Compare commits

..

62 commits

Author SHA1 Message Date
42dc26d4b0
Footer. Information about Breaking Changes and reference issues that this commit closes
All checks were successful
continuous-integration/drone/push Build is passing
2020-08-27 19:45:35 +02:00
ec77b1b5f9
Footer. Information about Breaking Changes and reference issues that this commit closes
All checks were successful
continuous-integration/drone/push Build is passing
2020-08-27 14:17:33 +02:00
0db8246af6
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-27 02:29:27 +02:00
01ead85fbd
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-27 02:11:38 +02:00
d10f98ced5
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-27 01:38:07 +02:00
efc19e8453
Footer. Information about Breaking Changes and reference issues that this commit closes
All checks were successful
continuous-integration/drone/push Build is passing
2020-08-27 01:25:44 +02:00
c959669767
m
Some checks reported errors
continuous-integration/drone/push Build was killed
2020-08-27 01:24:38 +02:00
b41d798479
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks reported errors
continuous-integration/drone/push Build was killed
2020-08-27 01:21:46 +02:00
9b7cce1f8c
Footer. Information about Breaking Changes and reference issues that this commit closes 2020-08-27 01:20:20 +02:00
e1e8ccb7c0
Footer. Information about Breaking Changes and reference issues that this commit closes 2020-08-27 01:19:39 +02:00
97c51c106b
Footer. Information about Breaking Changes and reference issues that this commit closes
All checks were successful
continuous-integration/drone/push Build is passing
2020-08-27 00:57:27 +02:00
c8b0d92709
Footer. Information about Breaking Changes and reference issues that this commit closes
All checks were successful
continuous-integration/drone/push Build is passing
2020-08-27 00:43:47 +02:00
d40d422e5e
Footer. Information about Breaking Changes and reference issues that this commit closes
All checks were successful
continuous-integration/drone/push Build is passing
2020-08-27 00:33:07 +02:00
2519dc731f
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-27 00:25:55 +02:00
ad25849cbe
Footer. Information about Breaking Changes and reference issues that this commit closes
All checks were successful
continuous-integration/drone/push Build is passing
2020-08-27 00:17:23 +02:00
d8a8c3746c
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-26 15:23:34 +02:00
14b0cb8c5e
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-26 14:51:54 +02:00
9b9ec49b24
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-26 14:37:46 +02:00
2b9d35af4a
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-26 01:36:12 +02:00
dc4247aca2
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-26 01:33:33 +02:00
dd7cd06e02
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-26 01:19:32 +02:00
efb2f38edd
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-26 01:13:37 +02:00
2c57b6f374
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-26 01:08:30 +02:00
e3eecbe64a
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-26 01:04:49 +02:00
f04d23b2bb
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-26 01:01:32 +02:00
9e18622d0e
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-26 00:55:59 +02:00
241af1239c
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-24 23:34:09 +02:00
d1d868e7e4
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-24 23:30:19 +02:00
b66e8eae06
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-24 23:05:09 +02:00
fb91c95613
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-24 22:54:27 +02:00
06cfa96c31
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-24 22:49:12 +02:00
b8a1cc3aa9
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-24 22:19:52 +02:00
341812ad24
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-24 22:17:01 +02:00
e30c93b457
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks reported errors
continuous-integration/drone/push Build encountered an error
2020-08-24 22:16:16 +02:00
e4440e7789
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-24 22:12:45 +02:00
40da4d73df
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-24 22:09:02 +02:00
94225d69ef
Footer. Information about Breaking Changes and reference issues that this commit closes
Some checks failed
continuous-integration/drone/push Build is failing
2020-08-24 21:57:23 +02:00
15618109f1
fix(org): fix urls 2020-08-24 21:33:47 +02:00
07b563b076
Footer. Information about Breaking Changes and reference issues that this commit closes 2020-08-22 13:27:33 +02:00
ef8f819042
Footer. Information about Breaking Changes and reference issues that this commit closes 2020-08-22 13:22:52 +02:00
2ac743f6f5
Footer. Information about Breaking Changes and reference issues that this commit closes 2020-08-22 13:20:50 +02:00
7904aefc49
asd 2020-08-22 13:13:38 +02:00
19e37bafa0
asd 2020-08-22 13:04:25 +02:00
59f4616aa6
asd 2020-08-22 12:57:19 +02:00
0b1ac496a5
asd 2020-08-22 11:07:08 +02:00
617e399e0d
test 2020-08-22 11:04:40 +02:00
5f8ee44857
more stuff 2020-08-22 10:57:38 +02:00
f702904eed
update links 2020-08-22 01:40:09 +02:00
19351eaac0
asd 2020-08-21 21:56:33 +02:00
90ae16925f
do more stuff 2020-08-21 21:56:11 +02:00
5b1f36ec59
Update 2020-08-21 20:29:36 +02:00
4a75b9f3ae
Update submodules 2020-08-21 20:24:15 +02:00
f09cc74dc8
bump 2020-08-21 20:19:40 +02:00
47ce34becb
Bump 2020-08-21 14:54:07 +02:00
b5fc1eb62b
Fix dockerfile 2020-08-21 08:13:18 +02:00
c2cfadb042
asd 2020-08-20 23:36:56 +02:00
52c8cfed18
asd 2020-08-20 23:33:53 +02:00
2e0ecf8bc8
asd 2020-08-20 23:31:18 +02:00
470150aef6
asd 2020-08-20 23:28:31 +02:00
a057bf3652
bump 2020-08-20 23:27:41 +02:00
a864ed8782
Change drone for gitlab-ci 2020-08-20 23:25:35 +02:00
d483a5f804
Big update after a lot of time 2020-08-20 22:28:10 +02:00
12 changed files with 265 additions and 1039 deletions

View file

@ -17,7 +17,7 @@ steps:
when:
event: push
branch:
- master
- develop
- testing
- name: "Test: Build docker image"
@ -34,5 +34,96 @@ steps:
when:
event: push
branch:
- master
- develop
- testing
- name: "Test: Deploy docker image"
image: appleboy/drone-ssh
settings:
host: daemons.it
username: drone
port: 6699
key:
from_secret: ssh_key
script:
- sudo docker pull registry.daemons.it/baddaemons:testing
- sudo systemctl restart docker-hugo-test
script_stop: true
when:
event: push
branch:
- develop
- testing
- name: "Test: Test page"
image: wjdp/htmltest
commands:
- htmltest -c .htmltest.yml
when:
event: push
branch:
- develop
- testing
- name: "Main: Clean"
image: alpine
commands:
- rm -r public
when:
event: push
branch: develop
- name: "Main: Build web"
image: plugins/hugo
settings:
hugo_version: 0.74.3
url: https://daemons.it
validate: true
when:
event: push
branch: develop
- name: "Main: Build docker image"
image: banzaicloud/drone-kaniko
settings:
username:
from_secret: docker_user
password:
from_secret: docker_password
repo: baddaemons
registry:
from_secret: docker_registry
tags: latest
when:
event: push
branch: develop
- name: "Main: Deploy docker image"
image: appleboy/drone-ssh
settings:
host: daemons.it
username: drone
port: 6699
key:
from_secret: ssh_key
script:
- sudo docker pull registry.daemons.it/baddaemons:latest
- sudo systemctl restart docker-hugo
script_stop: true
when:
event: push
branch: develop
- name: Notify
image: registry.daemons.it/drone-xmpp
environment:
XMPP_USER:
from_secret: xmpp_user
XMPP_PASSWORD:
from_secret: xmpp_password
XMPP_ROOM:
from_secret: xmpp_room
PLUGIN_MESSAGE: "Beep, boop, I'm a bot. The CI job finished: {build_status}\n- Job url: {build_link}"
when:
status: [success, failure]
event: push

View file

@ -6,6 +6,8 @@ theme:
- "after-dark"
pygmentsUseClasses: true
pygmentsCodeFences: true
pygmentsStyle: "monokai"
postNavigation: true
permalinks:

View file

@ -6827,84 +6827,3 @@ if err != nil {
Se lo enseñe a [[https://gnusocial.net/ameba][Ameba]] y como cualquier persona con ojos, se sintió muy ofendida por el "diseño". Por ello, hizo una primera implementación de [[https://bulma.io/][bulma]], un framework CSS como lo es bootstrap. Viendo que se habia tomado la molestia, por sentido de la vergüenza y por que en realidad soy consciente de que la UX es importante, decidí terminar de implementarlo (con mucha ayuda) y aprender bastante de conceptos básicos de html, css y js, que siempre voy muy pez. Y ha quedado algo más cuqui, como se puede ver en la primera imagen.
Poco más que añadir. Go me parece un lenguaje interesante y probablemente siga aprendiendo porque hace ya tiempo que quiero tener algún otro lenguaje a parte de python. Es improbable que Gomic reciba muchas más actualizaciones más allá de añadir más orígenes, pero cualquier sugerencia siempre será bienvenida.
* DONE Estandarizar commits en Magit con commitizen :magit:emacs:git:
:PROPERTIES:
:EXPORT_FILE_NAME: estandarizar-commits-en-magit-con-commitizen
:ARCHIVE_TIME: 2020-08-27 Thu 20:50
:ARCHIVE_FILE: ~/.syncthing/Casa/Proyectos/BadDaemons/content-org/articulos.org
:ARCHIVE_CATEGORY: articulos
:END:
Quién trabaje o contribuya a proyectos de software con otras personas sabrá que a veces el tiempo se va discutiendo chorradas. Un ejemplo típico son las convenciones del código.
Por ejemplo, en python lineas más largas de 79 carácteres (como el pep8 define) o más (ya que no estamos en los 90 y tenemos pantallas de más de 8 pulgadas)? Una lista debería estar en una sola línea o en varias?
Para la mayor parte de los casos no hay respuesta correcta, por que es cuestión de gustos. Por ello, ya hace un tiempo que decidí que paso de dedicar mi tiempo a esto y que otra persona decida por mi. En el caso de los ejemplos anteriores he decidido que sea [[https://github.com/psf/black][black]] quien decida como hacer las cosas. Pero yendo al articulo, he decidido que quién se encargue del formato de mis commits sea [[https://commitizen-tools.github.io/commitizen/][commitizen]].
Alredor del formato de los commits hay mucha historia. Lo idóneo es poner el tipo de cambio, el alcance de este, un título que resuma el cambio, un cuerpo con una explicación más profunda si hace falta y un ticket del gestor de tareas que uses. De esta forma es más fácil ver como evoluciona el código y la lógica que hay detrás. Tiene un añadido y es que si los commits tienen el mismo formato, se pueden generar changelogs de forma automática.
Meter toda esta información no es fácil. Para ello está [[https://commitizen-tools.github.io/commitizen/][commitizen]]. Esta herramienta da lo siguiente:
- [[https://www.conventionalcommits.org/en/v1.0.0/][Implementar una convencion de commits]]
- [[https://semver.org/][Gestión de versiones semántica]]
- [[https://keepachangelog.com/en/1.0.0/][Crear un changelog]]
=cz= es un plugin de git. En vez de usar `git commit` lo que hay que hacer es usar =git cz= y te hace una serie de preguntas que ayudarán a generar el mensaje. Se puede ver un ejemplo en esta imagen:
[[/img/commitizen.gif]]
Pero esta es una herramienta para la terminal, y teniendo emacs, la terminal está obsoleta. Así que veamos como usar esto en Magit. Lo idóneo sería llamar a =git cz= directamente, ya que aunque =cz= define las convenciones, estas se pueden cambiar por proyecto, por lo que generar una plantilla para el commit sin más puede no cubrir todos los casos. Estuve investigando cómo hacerlo pero tendría que haberme metido mucho más en la madriguera del conejo de lo que ya he hecho, por lo que decidí ir a por una solución de compromiso.
Por un lado, hice una plantilla para magit. Esto me servirá para la mayoría de los casos. Pero para cuando no, tengo una función que me deja hacer el commit desde emacs. No usa magit, lo cual es una pena, pero para el caso valdrá. Veamos ambas opciones.
He creado una función que usa [[https://github.com/joaotavora/yasnippet][yasnippet]], un sistema de plantillas. Luego se añade esa función al hook del git-commit y de esta forma cada vez que se haga un commit, se llama a la función:
#+BEGIN_SRC emacs-lisp
(defun daemons/commitizen-template()
"Expand a commitizen template."
(yas-expand-snippet "${1:Select the type of change you are committing: $$(yas-choose-value '(\"fix\" \"feat\" \"docs\" \"style\" \"refactor\" \"perf\" \"test\" \"build\" \"ci\"))}(${2:Scope. Could be anything specifying place of the commit change (users, db, poll): )}): ${3:Subject. Concise description of the changes. Imperative, lower case and no final dot}
${4:Body. Motivation for the change and contrast this with previous behavior}
${5:Footer. Information about Breaking Changes and reference issues that this commit closes}"))
(add-hook 'git-commit-setup-hook #'daemons/commitizen-template)
#+END_SRC
Para llamar a =cz= directamente he usado una función bonica que encontré en reddit (la fuente está en la función) que en resumen usa [[https://github.com/akermu/emacs-libvterm][vterm]] para lanzar una orden arbitrária. Creé la función chorra que llama a esa función con =cz= y ya está.
#+BEGIN_SRC emacs-lisp
(defun phalp/run-in-vterm (command)
"Execute string COMMAND in a new vterm.
From: https://www.reddit.com/r/emacs/comments/ft84xy/run_shell_command_in_new_vterm/
Interactively, prompt for COMMAND with the current buffer's file
name supplied. When called from Dired, supply the name of the
file at point.
Like `async-shell-command`, but run in a vterm for full terminal features.
The new vterm buffer is named in the form `*foo bar.baz*`, the
command and its arguments in earmuffs.
When the command terminates, the shell remains open, but when the
shell exits, the buffer is killed."
(interactive
(list
(let* ((f (cond (buffer-file-name)
((eq major-mode 'dired-mode)
(dired-get-filename nil t))))
(filename (concat " " (shell-quote-argument (and f (file-relative-name f))))))
(read-shell-command "Terminal command: "
(cons filename 0)
(cons 'shell-command-history 1)
(list filename)))))
(with-current-buffer (vterm (concat "*" command "*"))
(vterm-send-string command)
(vterm-send-return)))
(defun daemons/commitizen-gz() (interactive) (phalp/run-in-vterm "git cz commit; exit"))
#+END_SRC
Tiene pinta de que no integraré nunca magit con =cz= dada su dificultad, por lo que probablemente vaya creando plantillas para los commits según el proyecto y buscaré alguna forma de que use una plantilla u otra según el directorio en el que esté. Aún así molaria ver =cz= integrado.

File diff suppressed because it is too large Load diff

View file

@ -1,138 +0,0 @@
+++
title = "Antisocial - Analizar datos del fediverso"
author = ["drymer"]
lastmod = 2021-08-09T00:20:15+02:00
tags = ["antisocial", "fediverso"]
draft = false
+++
**Disclaimer**: Este artículo se ha escrito del tirón con cosas que tengo en mente desde hace mucho. Es posible que no sea del todo riguroso en algunos aspectos y que en alguno exagere. Intento simplificar cosas que son complejas de explicar, por lo que seguro que hay cosas que no son exactas.
## Tabla de contenido {#tabla-de-contenido}
- [Prólogo](#prólogo)
- [De quién nos protegemos?](#de-quién-nos-protegemos)
- [Definiciones de seguridad y anónimato](#definiciones-de-seguridad-y-anónimato)
- [Matriz para decidir como protegerte](#matriz-para-decidir-como-protegerte)
- [Antisocial: Qué datos se pueden sacar de las redes sociales libres?](#antisocial-qué-datos-se-pueden-sacar-de-las-redes-sociales-libres)
## Prólogo {#prólogo}
Qué diferencia una red social privativa de una red social libre? Se podría decir que la principal diferencia es que detrás de las redes privativas hay una o varias empresas con ánimo de lucro. Normalmente esto se traduce en que quieren recopilar cuantos más datos de sus usuarias. Pero que datos tienen realmente las empresas de nosotras?
Para simplificar la pregunta, vamos a reducir solamente al uso de la propia red social, sin entrar en [movidas de cookies](https://anytech365.com/es/stop-facebook-spying-on-you-outside-of-facebook/) de terceros ni nada parecido.
Qué datos puede ver facebook o twitter cuando usamos sus páginas?:
- El contenido de lo que públicamos, ya sea público o privado
- Interacciones (favoritos, compartir)
- Dónde ponemos el ratón y durante cuanto tiempo
- Que páginas miramos (perfiles privados, grupos, ...)
- Cuanto tiempo pasamos en cada página
- Anuncios que vemos
- Información física (IP desde la que te conectas)
Cuando lo comparamos con los datos que se pueden sacar del fediverso, vemos que en realidad de esa lista de seis, solo se cumplen dos. Contenido e interacciones. Desde luego es una mejora, motivo suficiente para no usar redes privativas. Está bien que no cojan tus datos y los usen para alimentar AIs malignas o venderlas a terceros.
## De quién nos protegemos? {#de-quién-nos-protegemos}
Pero que pasa con los datos que se comparten en las redes libres? Que daño podrían causar? Creo que para responder a esta pregunta correctamente, hay que hablar de algunos temas que a veces se mezclan:
- Enemigos o actores malignos
- Seguridad de la información
- Anonimato
Qué actores malignos podrian existir en general?
- **Un gobierno**: no son pocos los gobiernos que espian de forma masiva a sus ciudadanos con el fin de "protegerlos". Sobre este tema hay [información para aburrir](https://es.wikipedia.org/wiki/Revelaciones%5Fsobre%5Fla%5Fred%5Fde%5Fvigilancia%5Fmundial%5F(2013-2015)).
- **Una empresa**: las empresas de las redes sociales privativas recogen los datos para sí pero además los venden a otros. [Ejemplo reciente](https://time.com/6083323/bishop-pillar-grindr-data/), un cura denunciado por ser gay y ir a bares gays. La fuente de los datos? Datos disponibles a la venta por parte de Grindr.
- **Un particular**: normalmente esta persona no tiene interés en la recopilación de datos masiva, sinó en la recopilación de datos personales. Puede estar relacionado con ataques personales y doxxing. Un ejemplo, [Gamergate](http://www.mtv.com/news/2245633/gamer-gate-one-year-later/).
## Definiciones de seguridad y anónimato {#definiciones-de-seguridad-y-anónimato}
**Disclaimer**: Es un tochazo.
Una vez definidos los actores malignos, definamos las otras dos palabras, ya que a veces las mezclamos.
### Seguridad {#seguridad}
La [seguridad de la información](https://es.wikipedia.org/wiki/Seguridad%5Fde%5Fla%5Finformaci%C3%B3n), en el contexto del fediverso, está compuesta de las siguientes claves:
- **Confidencialidad**: Que la información llegue a quien tenga que llegar. La información pública la tenemos clara, la publicamos y la ve cualquiera. Luego hay otras formas de limitar quien puede ver que. Esta funcionalidad la tienen varias implementaciones, como Mastodon o Pleroma, y está cogida con pinzas. El problema es que en la federación, si mi servidor dice que algo es privado y se lo manda a otro servidor, este otro servidor tiene que respetarlo. Ejemplo, el usuario a del nodo manda un mensaje privado al usuario b del nodo b. El nodo b podría decidir hacer público este mensaje.
- **Integridad**: Que nadie pueda modificar nuestra información. El problema es similar al anterior, dentro de tu servidor controlas lo que quieras, pero cuando lo lanzas fuera hay que confiar. Ejemplo, el usuario a del nodo a lanza un mensaje al mundo y el nodo b modifica el mensaje para decir que odia las aceitunas.
- **Disponibilidad**: Que la información se pueda consultar cuando se requiera. Hay diferentes acercamientos en el fediverso, algunas implementaciones copian los datos (con la consecuencia sobrecarga) y aunque el origen falle, pueden mostrarlo. Otras simplemente referencian al origen.
- **Autenticación**: Que se pueda identificar a la persona que ha escrito la información. Esta parte es especialmente importante y se relaciona con el siguiente palabro, **anonimato**.
### Anonimato {#anonimato}
Qué significa **anonimato**? Incluso dentro del contexto de las redes libres, puede tener distintas connotaciones. Una parte del problema es que usamos la palabra **anónimo** cuando en realidad queremos decir **pseudoanónimo**. Una persona anónima es una persona que es de nombre desconocido o que se oculta, según la RAE. Pero entonces, como podemos garantizar la seguridad de la información? Una de las claves es la integridad y la autenticación. Como podemos saber que el mensaje es de quien dice ser, si no sabemos quien es?
Una primera diferenciación que tenemos que hacer es la de personas e identidades. Yo como persona soy lo que pone en mi DNI, pero tengo más identidades. Una es drymer, alguien que lleva en comunidades de software libre varios años y que tiene interéses y actividades x.
Pero no es la única identidad que tengo, tengo otros nicks y otras actividades. Estas identidades pueden ser o no **pseudoanonimas**. Digo pseudoanonimas por que necesitan un identificador. Por ejemplo, el identificador más viejo y fiable de drymer es mi correo eléctronico.
Más ejemplos de identidades pseudoanonimas. Un foro en la red de tor. Si yo me logue como paquito, yo ahí tendré la identidad de paquito. **Sabran** quien es mi identidad. Pero desde un punto de vista técnico, no sabran quien soy yo como persona, ya que Tor se asegura de ello.
Llevando la definición a las redes libres, seremos **anónimas** si usamos herramientas para tal fin (tor, vpns, 7 proxies, etc...). Pero tendremos una identidad identificable, valga la redundancia, que será la que usaremos para iniciar sesión en uno de los nodos del fediverso. Por ejemplo, mi identidad será drymer@barcelona.social.
## Matriz para decidir como protegerte {#matriz-para-decidir-como-protegerte}
Después de todo ese desvarío, que creo era necesario, vamos a ver como facilitarnos un poco la vida. He aquí una matriz para escoger que cosas podemos hacer según de quien nos queremos proteger:
- RSP: Red social privativa.
- RSL: Red social libre.
- PH: Protección por herramientas, como tor, proxies, vpns,...
- PC: Protección por contenido, no decir direcciones físicas, nombres, gustos personales, etc.
- IC: Irse a vivir a una cueva, plantar zanahorias y tomates.
| De quien me protejo? | RSP + PH | RSP + PC | RSP + PH + PC | RSL + PH | RSL + PC | RSL + PH + PC | Irse a vivir a una cueva |
|----------------------------|----------|----------|---------------|----------|----------|---------------|--------------------------|
| De un gobierno | | | X | | | X | X |
| De las empresas | X | X | X | | X | | X |
| De una persona / colectivo | | X | | | X | | X |
| Del mundo | | | | | | | X |
Hay bastante a desgranar:
- **Gobierno**: Tenemos que usar herramientas de ocultación tanto física como mediante el contenido. Esta última parte suele ser en la que se falla. Si coges y pones en tu red social favorita del fediverso que te vas a tomar un helado a la plaza del Sol, ya puedes usar tor que te van a poder encontrar igual. Por ello, ambos métodos de ocultación son absolutamente necesarios para usar tanto redes socialas privativas como libres. Si una de los dos métodos de ocultación falla, estarás expuesta.
- **Empresas**: En general, como individuos somos irrelevantes (salvo excepciones, como la del cura de grindr). No les interesa Paco Perez, les interesa su edad, sexo, género y gustos. Y todo ello se puede conseguir tanto en redes sociales como privadas (aunque en mayor medida en las privativas). Si compartes una foto de la compra en la tienda del barrio para hacerles promoción, les estás diciendo tus gustos. Aunque sea una red social libre, son datos accesibles públicos. Por ello, uses la red que uses, si quieres protegerte de una empresa debes enmascarar tus datos. Usar protección de herramientas puede ser útil, pero no es la parte gorda de la que sacan tu información.
- **Persona / colectivo**: En este caso da igual si usas redes privadas o libres, por que no tienen acceso a los servidores (a menos que hablemos de juankers malosos), a diferencia de los dos anteriores. De lo que se alimentan estos actores es del contenido de tus publicaciones. Por ello, en este caso, es irrelevante si usas una red social privada o pública. Lo importante es qué publicas en ellas y si pueden llegar a encontrar tus otras identidades, ya sea la física u otras identidades virtuales. Por lo tanto, la principal protección es la de protección por contenido.
- **Mundo**: Papel de aluminio en la cabeza y al monte, poco más hay que hacer.
Si lo pensamos, los actores se diferencian solamente en el grado de recursos y de cosas ilegales que están dispuestos a hacer. Un gobierno siempre tendrá más recursos que una persona. Aunque una persona o un grupo de personas con la suficiente motivación pueden tocar las narices igual.
PD: algo que se puede ver en la matriz es que la solución a todos los problemas es irse a vivir a una cueva...
## Antisocial: Qué datos se pueden sacar de las redes sociales libres? {#antisocial-qué-datos-se-pueden-sacar-de-las-redes-sociales-libres}
Todo este tocho y yo en verdad venia a hablar de mi libro. Hace tiempo que me preocupa que nos pensemos que las redes sociales libres son seguras y anónimas, por que no lo son.
Estan sujetas a leyes, por lo que en el mejor de los casos tenemos que confiar en que los colectivos que las mantienen **rompan** la ley si tienen algún requerimiento legal. Algo que es mucho más fácil de decir que hacer. Por no hablar del peor de los males, que somos nosotras mismas. Somos nosotras quienes damos más información en nuestras publicaciones. Es este tema en concreto en el que yo quiero profundizar.
Como prueba de concepto, he pedido a unas buenas gentes del fediverso que me dejen descargar sus datos públicos y meterlos en una aplicación que he desarrollado que los trata. Hace dos cosas, mostrar una nube de palabras con sus palabras más usadas y muestra un gráfico de relaciones. En este gráfico de relaciones se ve con quien han interactuado, ya sea con reposts, favoritos o menciones.
Quiero agradecer a todas las personas que han ofrecido sus datos. Al final he cogido solo algunas pocas, tanto por facilidad como por problemas técnicos. Estas son:
- <https://pleroma.libretux.com/@anoncf>
- <https://mastodon.lol/@dark>
- <https://todon.nl/@talogeta>
- <https://mastodon.madrid/@notxor>
- <https://pleroma.libretux.com/@izaro>
- <https://qoto.org/@qapaq>
Quiero recalcar la parte en la que esta buena gente me ha permitido descargar sus datos. Me han dicho que si, pero no han tenido que hacer nada, por que yo podria haberlos descargados sin más. Si fuese un actor maligno, no se habrian enterado.
Para cerrar, hay dos temas de los cuales me parece interesante hablar, por lo que crearé dos hilos en el fediverso para ello:
- Las redes sociales (libres o privativas), tiene ventajas y desventajas. Cúal es el balance? Los peligros en los que nos ponen sobrepasan las ventajas? El hilo es [este](https://barcelona.social/notice/AA82X5uJC1p9pKkk0O).
- Que opinais de que se publique una herramienta que permita descargar y tratar los datos del fediverso? Concretamente hablo de **antisocial**, que es la herramienta que he desarrollado. El hilo es [este](https://barcelona.social/notice/AA82aSoAVK63ioUHx2).
Sin más dilación, sacad vuestras conclusiones. Los datos y parte de se puede consultar [aquí](https://antisocial.daemons.it).

View file

@ -1,15 +0,0 @@
+++
title = "Cómo diseñar un rol de ansible - 1"
author = ["drymer"]
lastmod = 2021-11-28T18:24:41+01:00
tags = ["ansible", "desarrollo"]
draft = false
+++
He empezado una serie de videos en Peertube en los que explicaré como diseñar un rol de ansible.
El fin no es tanto cómo hacer un rol, ya que hay mucha documentación sobre el tema, sinó intentar mostrar el hilo del pensamiento cuando te encuentras con la necesidad de automatizar algo que tal vez no conozcas mucho y diseñar como será la interfaz para el usuario.
Peertube es compatible con cualquier implementación del fediverso, por lo que se puede [suscribir al canal](https://fediverse.tv/c/bad%5Fdaemons/videos) desde el botón de "Subscribe".
<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts allow-popups" title="Cómo diseñar un rol de ansible - 1" src="<https://fediverse.tv/videos/embed/0dc56409-bc6a-4b0f-838f-57ac2913d80e>" frameborder="0" allowfullscreen></iframe>

View file

@ -1,81 +0,0 @@
+++
title = "Estandarizar commits en Magit con commitizen"
author = ["drymer"]
lastmod = 2020-08-27T20:47:43+02:00
tags = ["magit", "emacs", "git"]
draft = false
+++
Quién trabaje o contribuya a proyectos de software con otras personas sabrá que a veces el tiempo se va discutiendo chorradas. Un ejemplo típico son las convenciones del código.
Por ejemplo, en python lineas más largas de 79 carácteres (como el pep8 define) o más (ya que no estamos en los 90 y tenemos pantallas de más de 8 pulgadas)? Una lista debería estar en una sola línea o en varias?
Para la mayor parte de los casos no hay respuesta correcta, por que es cuestión de gustos. Por ello, ya hace un tiempo que decidí que paso de dedicar mi tiempo a esto y que otra persona decida por mi. En el caso de los ejemplos anteriores he decidido que sea [black](https://github.com/psf/black) quien decida como hacer las cosas. Pero yendo al articulo, he decidido que quién se encargue del formato de mis commits sea [commitizen](https://commitizen-tools.github.io/commitizen/).
Alredor del formato de los commits hay mucha historia. Lo idóneo es poner el tipo de cambio, el alcance de este, un título que resuma el cambio, un cuerpo con una explicación más profunda si hace falta y un ticket del gestor de tareas que uses. De esta forma es más fácil ver como evoluciona el código y la lógica que hay detrás. Tiene un añadido y es que si los commits tienen el mismo formato, se pueden generar changelogs de forma automática.
Meter toda esta información no es fácil. Para ello está [commitizen](https://commitizen-tools.github.io/commitizen/). Esta herramienta da lo siguiente:
- [Implementar una convencion de commits](https://www.conventionalcommits.org/en/v1.0.0/)
- [Gestión de versiones semántica](https://semver.org/)
- [Crear un changelog](https://keepachangelog.com/en/1.0.0/)
`cz` es un plugin de git. En vez de usar \`git commit\` lo que hay que hacer es usar `git cz` y te hace una serie de preguntas que ayudarán a generar el mensaje. Se puede ver un ejemplo en esta imagen:
{{< figure src="/img/commitizen.gif" >}}
Pero esta es una herramienta para la terminal, y teniendo emacs, la terminal está obsoleta. Así que veamos como usar esto en Magit. Lo idóneo sería llamar a `git cz` directamente, ya que aunque `cz` define las convenciones, estas se pueden cambiar por proyecto, por lo que generar una plantilla para el commit sin más puede no cubrir todos los casos. Estuve investigando cómo hacerlo pero tendría que haberme metido mucho más en la madriguera del conejo de lo que ya he hecho, por lo que decidí ir a por una solución de compromiso.
Por un lado, hice una plantilla para magit. Esto me servirá para la mayoría de los casos. Pero para cuando no, tengo una función que me deja hacer el commit desde emacs. No usa magit, lo cual es una pena, pero para el caso valdrá. Veamos ambas opciones.
He creado una función que usa [yasnippet](https://github.com/joaotavora/yasnippet), un sistema de plantillas. Luego se añade esa función al hook del git-commit y de esta forma cada vez que se haga un commit, se llama a la función:
```emacs-lisp
(defun daemons/commitizen-template()
"Expand a commitizen template."
(yas-expand-snippet "${1:Select the type of change you are committing: $$(yas-choose-value '(\"fix\" \"feat\" \"docs\" \"style\" \"refactor\" \"perf\" \"test\" \"build\" \"ci\"))}(${2:Scope. Could be anything specifying place of the commit change (users, db, poll): )}): ${3:Subject. Concise description of the changes. Imperative, lower case and no final dot}
${4:Body. Motivation for the change and contrast this with previous behavior}
${5:Footer. Information about Breaking Changes and reference issues that this commit closes}"))
(add-hook 'git-commit-setup-hook #'daemons/commitizen-template)
```
Para llamar a `cz` directamente he usado una función bonica que encontré en reddit (la fuente está en la función) que en resumen usa [vterm](https://github.com/akermu/emacs-libvterm) para lanzar una orden arbitrária. Creé la función chorra que llama a esa función con `cz` y ya está.
```emacs-lisp
(defun phalp/run-in-vterm (command)
"Execute string COMMAND in a new vterm.
From: https://www.reddit.com/r/emacs/comments/ft84xy/run_shell_command_in_new_vterm/
Interactively, prompt for COMMAND with the current buffer's file
name supplied. When called from Dired, supply the name of the
file at point.
Like `async-shell-command`, but run in a vterm for full terminal features.
The new vterm buffer is named in the form `*foo bar.baz*`, the
command and its arguments in earmuffs.
When the command terminates, the shell remains open, but when the
shell exits, the buffer is killed."
(interactive
(list
(let* ((f (cond (buffer-file-name)
((eq major-mode 'dired-mode)
(dired-get-filename nil t))))
(filename (concat " " (shell-quote-argument (and f (file-relative-name f))))))
(read-shell-command "Terminal command: "
(cons filename 0)
(cons 'shell-command-history 1)
(list filename)))))
(with-current-buffer (vterm (concat "*" command "*"))
(vterm-send-string command)
(vterm-send-return)))
(defun daemons/commitizen-gz() (interactive) (phalp/run-in-vterm "git cz commit; exit"))
```
Tiene pinta de que no integraré nunca magit con `cz` dada su dificultad, por lo que probablemente vaya creando plantillas para los commits según el proyecto y buscaré alguna forma de que use una plantilla u otra según el directorio en el que esté. Aún así molaria ver `cz` integrado.

View file

@ -1,208 +0,0 @@
+++
title = "Gestión de paquetes y dotfiles en arch"
author = ["drymer"]
lastmod = 2021-08-25T00:17:38+02:00
tags = ["arch"]
draft = false
+++
<div class="ox-hugo-toc toc">
<div></div>
<div class="heading">&Iacute;ndice</div>
- [TL;DR](#tl-dr)
- [Prólogo](#prólogo)
- [Diferencia entre herramientas imperativas y herramientas declarativas](#diferencia-entre-herramientas-imperativas-y-herramientas-declarativas)
- [Aconfmgr y brew](#aconfmgr-y-brew)
- [Dotfiles](#dotfiles)
- [Empaquetado](#empaquetado)
</div>
<!--endtoc-->
## TL;DR {#tl-dr}
Antes usaba ansible para gestionar los paquetes de mi SO y mis dotfiles y no me gustaba. Cambié de ansible a `aconfmgr`, `brew` y `stow`. Aquí se puede ver lo [viejo](https://git.disroot.org/drymer/dotfiles/src/commit/37ef0175848c3d4ea6e5ae63e2a4883b68afdd2f) y aquí lo [nuevo](https://git.disroot.org/drymer/dotfiles).
## Prólogo {#prólogo}
Hace tiempo me di cuenta de que me le dedicaba mucho tiempo a personalizar mi ordenador. Configuraciones varias, scripts, alias, programas, etc. Muchos de los programas no estaban en los repositorios comunes, ya que por aquel entonces aún usaba debian. Y mi solución fue hacer bastantes roles de ansible y un playbook de ansible que me gestionase todo. Tanto la instalación de todos los paquetes (algunos compilados, descargados de no se donde, etc) como de las configuraciones. Hice [este articulo](https://daemons.it/posts/como-gestionar-las-configuraciones-y-programas-de-tu-ordenador-con-ansible/), de hecho. El repositorio git ya no está en la misma dirección, pero el código se puede ver [aquí](https://git.disroot.org/drymer/dotfiles/src/commit/37ef0175848c3d4ea6e5ae63e2a4883b68afdd2f).
En ese momento me venia muy bien, por que necesitaba aprender [ansible](https://www.ansible.com/) y como cualquier tonto con un martillo, todo lo que veia eran clavos. Pero la realidad es que ansible no es la mejor herramienta para este tipo de cosas, sobretodo si hablamos de ordenadores personales.
Entre eso y que debian es leeeeeento a la hora de actualizar paquetes, hay pocos repositorios no oficiales (o menos), decidí pasarme a Arch.
Arch tiene el gestor de paquetes oficial, `pacman`. Y además, como Slackware, tiene un repositorio de paquetes hechos por la comunidad, llamado [Aur](https://aur.archlinux.org/). Tienen menos calidad que cualquier paquete de oficial de Arch o de Debian, pero ahí están. No es raro que algún paquete se te rompa al actualizar y tengas que hacer algún apaño o abrir un issue. Hay varias opciones para instalar paquetes de Aur, ir a pelo y clonar el repositorio git y ejecutar las órdenes o usar un gestor de paquetes. Han habido muchos a lo largo de los años, como pacaur o yaourt.
Pero hace un tiempo está [yay](https://github.com/Jguer/yay). Las ventajas de yay es que tiene los mismos parámetros que `pacman`, por lo que es fácil de usar. Y lo mejor, se sincroniza con `pacman`. Osea que cuando haces la típica actualización de sistema de `sudo pacman -Syu`, también te actualiza los paquetes de Aur. Muy útil.
Pero aún así se me quedaba corto, aún con lo grande que es Aur, le siguen faltando paquetes. Y por ello el resto los complemento con [Homebrew](https://brew.sh/). Homebrew nació como el gestor de paquetes que MacOS no tenia y necesitaba, pero con el tiempo se hizo compatible con GNU/Linux. No es mi preferido, ya que usa dependencias estáticas. Esto significa que si instalas el paquete `yamllint` de `brew`, como tiene de dependencia Python, te descargará python para que puedas usar `yamllint`, aunque tu distribución ya tenga python. Hay formas de evitar que lo haga, pero es incómodo y depende de la fórmula igual no puedes hacerlo. Por lo tanto, es la peor de las 3 opciones, aunque sigue siendo una opción, ya que no necesita root, es rápido y no da problemas.
Aún así, seguía con el problema de como reproducir los programas que tengo instalado. Decidí que en vez de una herramienta imperativa como es Ansible, lo que necesitaba era una herramienta declarativa. Tras luchar mucho para no saltar a [Guix](https://guix.gnu.org/), que gestiona todo el sistema operativo de forma declarativa, con rollback incluido, busque otras herramientas en Arch. Y encontré lo que buscaba, [aconfmgr](https://github.com/CyberShadow/aconfmgr) y vi que brew tiene esa misma funcionalidad metida, llamada [bundle](https://github.com/Homebrew/homebrew-bundle).
## Diferencia entre herramientas imperativas y herramientas declarativas {#diferencia-entre-herramientas-imperativas-y-herramientas-declarativas}
Antes de entrar en las herramientas, hablemos de las diferencias entre una herramienta imperativa y otra declarativa. Una herramienta imperativa "ordena" que hagas cosas. Si tu borras una orden, esta no se deshace la próxima vez que la ejecutes, sinó que simplemente no se ejecuta. Por ejemplo, si yo tengo un script así:
```bash
mkdir -p ejemplo/loQueSea
echo "holi" > ejemplo/loQueSea
```
Ejecuto el script y decido que no me gusta esa ruta y que quiero cambiarla:
```bash
mkdir -p ejemplo/estoMolaMas
echo "holi" > ejemplo/estoMolaMas
```
Al ejecutar el siguiente script, no deshacemos el primero. Es decir, sigue existiendo `ejemplo/loQueSea` con el contenido `holi`.
En cambio, una herramienta declarativa habria borrado el fichero `ejemplo/loQueSea`. De una forma mágica y transparente para nosotras, al ejecutar el primer script habria hecho algo como:
```bash
cambioAHacer=ejemplo/loQueSea
mkdir -p $camgioAHacer
echo "holi" > $cambioAHacer
```
Y al ejecutarlo por segunda vez, de forma mágica y transparente habria hecho:
```bash
rm $cambioAHacer
cambioAHacer=ejemplo/estoMolaMas
mkdir -p $camgioAHacer
echo "holi" > $cambioAHacer
```
Sé que es un ejemplo cogido con pinzas, pero espero que quede clara la diferencia.
De una forma más practica, si yo con ansible tenia una lista de paquetes tales como:
- git
- curl
- zsh
Y lo ejecutaba, me los instalaba. Pero si luego cambiaba la lista a:
- git
- curl
No me desinstalaba zsh.
En cambio, con herramientas declarativas como `aconfmgr` si lo hace.
## Aconfmgr y brew {#aconfmgr-y-brew}
Después de este intento de explicar las diferencias entre herramientas imperativas y declarativas, vamos al turrón. Con `aconfmgr`, tengo un ficherito tal que así:
```text
AddPackage base # Minimal package set to define a basic Arch Linux installation
AddPackage acpi # Client for battery, power, and thermal readings
AddPackage alacritty # A cross-platform, GPU-accelerated terminal emulator
AddPackage alsa-utils # Advanced Linux Sound Architecture - Utilities
IgnorePackage amd-ucode # Microcode update image for AMD CPUs
AddPackage arandr # Provide a simple visual front end for XRandR 1.2.
AddPackage archlinux-themes-slim # Arch Linux branded themes for the SLiM login manager
```
Es gigante y aburrido. Hacer la lista manualmente es una locura, por lo que el primer paso es hacer un dump de todo lo que tengas con `aconfmgr save`. Esto te creará un fichero llamado `99-unsorted.sh`. La idea es que en tu directorio de `aconfmgr` cojas los chorrocientos paquetes de ese fichero y los partas en varios, dividiendo de alguna forma razonable. Uno de mis ficheros es [este](https://git.disroot.org/drymer/dotfiles/src/branch/master/packages/arch/70-development.sh), y he estructurado así el directorio:
```text
arch
├── 1-ignore.sh
├── 10-base.sh
├── 15-utils.sh
├── 30-gui.sh
├── 50-media.sh
├── 70-development.sh
└── 90-misc.sh
```
`aconfmgr` también te gestiona los ficheros de configuración, pero yo he decidido no usar esa funcionalidad, por eso en el fichero `1-ignore.sh` ignoro todos los ficheros.
Una vez organizaditos, sólo queda aplicar los paquetes. Esto se hace con `aconfmgr apply`. Cuidado al hacer esto por primera vez, sobretodo si habéis hecho limpieza al hacer dump. Puede que intente reinstalar paquetes. A mi me la lió la primera vez y tuve que reinstalar el kernel.
Y con esto, ya tendriamos gestionados los paquetes de Arch. Ahora van los de `brew`. El concepto es el mismo, se hace un dump, se limpia y se aplica. Se vuelcan los paquetes instalados con `brew bundle dump`. Esto crea un fichero llamado `Brewfile`. Lo modificamos como querramos y para aplicarlo se ejecuta `brew bundle install`. Si se quiere borrar cualquier paquete que no esté declarado ahí, se puede ejecutar `brew bundle cleanup`.
## Dotfiles {#dotfiles}
Hasta ahora hemos hablado solo de los paquetes del SO, nada de dotfiles. Esto era lo que peor llevaba ansible, por que al final solo se trataba de hacer enlaces simbólicos y se le daban regular los cambios.
Ahora uso GNU Stow, que es más viejo que cagar sentado, que dicen en mi tierra. Pero hace lo que tiene que hacer, pone los ficheritos que tu quieres en su ruta. Está en todos los repositorios, por lo que se puede instalar con `pacman`.
La idea es crear una estructura de directorios en los que separas según alguna lógica. Yo me he decidido por esta estructura:
```bash
dotfiles
├── git
│   ├── .compartido
│   │   ├── Proyectos
│   │   │   ├── alias
│   │   │   │   └── .gitconfig
│   │   │   └── real
│   │   │   └── .gitconfig
│   │   └── Trabajo
│   │   └── .gitconfig
│   └── .gitconfig
├── i3
│   ├── .compton.conf
│   ├── .config
│   │   ├── dunst
│   │   │   └── dunstrc
│   │   ├── i3status.conf
│   │   └── rofi
│   │   └── config
│   ├── .i3
│   │   ├── config
│   │   └── scripts
│   │   ├── autolock.sh
│   │   ├── battery
│   │   ├── date
│   │   ├── lock
│   │   ├── sensors
│   │   └── volume-pulseaudio
│   └── .i3blocks.conf
└── shells
├── .alacritty.yml
├── .aliases
├── .bashrc
├── .config
│   └── starship.toml
├── .functions
├── .Xmodmap
└── .zshrc
```
La idea es fácil, tres directorios principales: git, i3 y shells. En estos, se reproduce la estructura del directorio en el que querrás colocar las configuraciones. Por ejemplo, todas mis configuraciones van bajo el $HOME. Entonces, si yo quiero tener en mi $HOME el fichero `.alacritty.yml`, en el directorio shells lo pongo tal cual, en `.alacritty.yml`.
Cuando tienes la estructura hecha, solo queda ejecutar stow. En mi caso:
```bash
stow -t ~ git
stow -t ~ i3
stow -t ~ shells
```
Y ale, los dotfiles instalados.
PD: La parte de git no la veréis completa en mi repositorio, ya que ahí salen mi nombre real que uso tanto para el trabajo como para proyectos personales que hago bajo mi nombre. Pero el resto es tal cual.
## Empaquetado {#empaquetado}
La idea es que todo esto sea fácil tanto de mantener como de instalar en un ordenador nuevo, por lo que habrá que usar algo de pegamento para unirlo. Por ello, he hecho un script que se puede consultar [aquí](https://git.disroot.org/drymer/dotfiles/src/branch/master/manage.sh). Nada como usar bash como buen pegamento.
Este script acepta los siguientes parámetros a día de hoy:
- ****install-packages****: Instalar todas las herramientas necesarias (aconfmgr, brew, yay y oh-my-zsh por que si).
- ****diff-bundle****: Mostrar las diferencias en los paquetes instalados y los declarados.
- ****apply-bundle****: Aplicar los paquetes declarados.
- ****update-bundle****: Actualizar el sistema operativo.
- ****dotfiles****: Instalar los dotfiles.

View file

@ -4,7 +4,7 @@ author = ["drymer"]
date = 2015-04-30T19:15:00+02:00
draft = false
tags = ["sysadmin", "elbinario"]
url = "/posts/spigot:-publicando-feeds-en-pump-io/"
url = "/posts/cosillas-de-emacs-escapar-simbolos-al-usar-usar-marcado-en-org-mode/"
+++
Andaba pensando en hacer algo similar a [gnusrss](https://elbinario.net/2015/02/11/gnusrss-publicando-feeds-en-gnu-social/) pero para [Pump.io](https://elbinario.net/?s%3Dpump), pero pude ahorrarmelo al preguntar en [la sala de redeslibres](https://www.mijabber.es/jappix/?r%3Dredeslibres@salas.mijabber.es) y saber de la existencia de [Spigot](https://pypi.python.org/pypi/spigot). Este programa hace lo que promete, publicar los feeds en Pump.io pero además con una particularidad, se encarga de hacerlo sin floodear la cuenta, por si el RSS en cuestión tiene muchas actualizaciones.

View file

@ -30,7 +30,7 @@
<div itemprop="articleBody">
{{ .Content }}
<div>Cualquier duda o comentario, me puedes contactar en los canales descritos en la <a href="/">página principal</a></div>
<div>Cualquier duda, se puede preguntar aquí o en los canales descritos en la <a href="/">página principal</a></div>
</div>
<footer>
<hr>

View file

@ -1,82 +1,2 @@
/* Background */ .chroma { color: #ffffff; background-color: #111111 }
/* Other */ .chroma .x { }
/* Error */ .chroma .err { }
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; }
/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #ffffcc }
/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* Keyword */ .chroma .k { color: #fb660a; font-weight: bold }
/* KeywordConstant */ .chroma .kc { color: #fb660a; font-weight: bold }
/* KeywordDeclaration */ .chroma .kd { color: #fb660a; font-weight: bold }
/* KeywordNamespace */ .chroma .kn { color: #fb660a; font-weight: bold }
/* KeywordPseudo */ .chroma .kp { color: #fb660a }
/* KeywordReserved */ .chroma .kr { color: #fb660a; font-weight: bold }
/* KeywordType */ .chroma .kt { color: #cdcaa9; font-weight: bold }
/* Name */ .chroma .n { }
/* NameAttribute */ .chroma .na { color: #ff0086; font-weight: bold }
/* NameBuiltin */ .chroma .nb { }
/* NameBuiltinPseudo */ .chroma .bp { }
/* NameClass */ .chroma .nc { }
/* NameConstant */ .chroma .no { color: #0086d2 }
/* NameDecorator */ .chroma .nd { }
/* NameEntity */ .chroma .ni { }
/* NameException */ .chroma .ne { }
/* NameFunction */ .chroma .nf { color: #ff0086; font-weight: bold }
/* NameFunctionMagic */ .chroma .fm { }
/* NameLabel */ .chroma .nl { }
/* NameNamespace */ .chroma .nn { }
/* NameOther */ .chroma .nx { }
/* NameProperty */ .chroma .py { }
/* NameTag */ .chroma .nt { color: #fb660a; font-weight: bold }
/* NameVariable */ .chroma .nv { color: #fb660a }
/* NameVariableClass */ .chroma .vc { }
/* NameVariableGlobal */ .chroma .vg { }
/* NameVariableInstance */ .chroma .vi { }
/* NameVariableMagic */ .chroma .vm { }
/* Literal */ .chroma .l { }
/* LiteralDate */ .chroma .ld { }
/* LiteralString */ .chroma .s { color: #0086d2 }
/* LiteralStringAffix */ .chroma .sa { color: #0086d2 }
/* LiteralStringBacktick */ .chroma .sb { color: #0086d2 }
/* LiteralStringChar */ .chroma .sc { color: #0086d2 }
/* LiteralStringDelimiter */ .chroma .dl { color: #0086d2 }
/* LiteralStringDoc */ .chroma .sd { color: #0086d2 }
/* LiteralStringDouble */ .chroma .s2 { color: #0086d2 }
/* LiteralStringEscape */ .chroma .se { color: #0086d2 }
/* LiteralStringHeredoc */ .chroma .sh { color: #0086d2 }
/* LiteralStringInterpol */ .chroma .si { color: #0086d2 }
/* LiteralStringOther */ .chroma .sx { color: #0086d2 }
/* LiteralStringRegex */ .chroma .sr { color: #0086d2 }
/* LiteralStringSingle */ .chroma .s1 { color: #0086d2 }
/* LiteralStringSymbol */ .chroma .ss { color: #0086d2 }
/* LiteralNumber */ .chroma .m { color: #0086f7; font-weight: bold }
/* LiteralNumberBin */ .chroma .mb { color: #0086f7; font-weight: bold }
/* LiteralNumberFloat */ .chroma .mf { color: #0086f7; font-weight: bold }
/* LiteralNumberHex */ .chroma .mh { color: #0086f7; font-weight: bold }
/* LiteralNumberInteger */ .chroma .mi { color: #0086f7; font-weight: bold }
/* LiteralNumberIntegerLong */ .chroma .il { color: #0086f7; font-weight: bold }
/* LiteralNumberOct */ .chroma .mo { color: #0086f7; font-weight: bold }
/* Operator */ .chroma .o { }
/* OperatorWord */ .chroma .ow { }
/* Punctuation */ .chroma .p { }
/* Comment */ .chroma .c { color: #008800; background-color: #0f140f; font-style: italic }
/* CommentHashbang */ .chroma .ch { color: #008800; background-color: #0f140f; font-style: italic }
/* CommentMultiline */ .chroma .cm { color: #008800; background-color: #0f140f; font-style: italic }
/* CommentSingle */ .chroma .c1 { color: #008800; background-color: #0f140f; font-style: italic }
/* CommentSpecial */ .chroma .cs { color: #008800; background-color: #0f140f; font-style: italic }
/* CommentPreproc */ .chroma .cp { color: #ff0007; background-color: #0f140f; font-weight: bold; font-style: italic }
/* CommentPreprocFile */ .chroma .cpf { color: #ff0007; background-color: #0f140f; font-weight: bold; font-style: italic }
/* Generic */ .chroma .g { }
/* GenericDeleted */ .chroma .gd { }
/* GenericEmph */ .chroma .ge { }
/* GenericError */ .chroma .gr { }
/* GenericHeading */ .chroma .gh { font-weight: bold }
/* GenericInserted */ .chroma .gi { }
/* GenericOutput */ .chroma .go { color: #444444; background-color: #222222 }
/* GenericPrompt */ .chroma .gp { }
/* GenericStrong */ .chroma .gs { }
/* GenericSubheading */ .chroma .gu { font-weight: bold }
/* GenericTraceback */ .chroma .gt { }
/* GenericUnderline */ .chroma .gl { }
/* TextWhitespace */ .chroma .w { color: #888888 }
img {width:100%;height: auto} .highlight,pre.highlight{background:#283c34;color:#abb2bf}.highlight pre{background:#282c34}.highlight .ge{font-style:italic}.highlight .gs{font-weight:700}.highlight .ow{font-weight:700}.highlight .n,.highlight .nf,.highlight .nn,.highlight .o,.highlight .p{color:#abb2bf}.highlight .c,.highlight .c1,.highlight .cm,.highlight .cp,.highlight .cs{color:#5c6370;font-style:italic}.highlight .sr,.highlight .ss{color:#56b6c2}.highlight .k,.highlight .kc,.highlight .kd,.highlight .kn,.highlight .kp,.highlight .kr,.highlight .kt{color:#c678dd}.highlight .l,.highlight .ld,.highlight .s,.highlight .s1,.highlight .s2,.highlight .sb,.highlight .sc,.highlight .sd,.highlight .se,.highlight .sh,.highlight .si,.highlight .sx{color:#98c379}.highlight .nt,.highlight .nx,.highlight .vi{color:#e06c75}.highlight .il,.highlight .m,.highlight .mf,.highlight .mh,.highlight .mi,.highlight .mo,.highlight .na{color:#d19a66}.highlight .bp,.highlight .nb,.highlight .nc,.highlight .nd,.highlight .ne,.highlight .ni,.highlight .nl,.highlight .no,.highlight .nv,.highlight .py,.highlight .vc,.highlight .vg{color:#e5c07b}.highlight .err{color:#fff;background-color:#e05252}.highlight .gd{color:#e05252}.highlight .gi{color:#43d08a}.highlight .w{color:#f8f8f2}.highlight .cpf{color:navy}.highlight .gu{color:#75715e}.highlight .lineno{color:#636d83;user-select:none}.highlight .ln{color:#636d83;user-select:none}.highlight .ln:after{content:" "}.highlight .hll{color:#abb2bf;background-color:#3a3f4b}.highlight .hl{color:#abb2bf;background-color:#3a3f4b}.highlight .language-json .w+.s2{color:#e06c75}.highlight .language-json .kc{color:#56b6c2}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 684 KiB