diff --git a/README.md b/README.md
index 351c92230..a8d16405e 100644
--- a/README.md
+++ b/README.md
@@ -5,8 +5,8 @@ For now the rest of this readme will probably be my cheatsheet/todo list.
# Tools used
-- The [newcss](https://newcss.net/) css framework.
-- The [eleventy](https://www.11ty.dev/) static site generator.
+- The [newcss](https://newcss.net/) css framework.
+- The [eleventy](https://www.11ty.dev/) static site generator.
# Commands
@@ -28,9 +28,9 @@ Github pages serves the `gh-pages` branch. The deployment is automated with Gith
In [`.deploy.yml`](https://github.com/statox/blog/blob/master/.github/workflows/deploy.yml) I use the github pages provider which does the following:
- - Install everything
- - Use `npm run build` to generate the site in the `docs/` directory
- - Checkout the result on the `gh-pages` branch
+- Install everything
+- Use `npm run build` to generate the site in the `docs/` directory
+- Checkout the result on the `gh-pages` branch
## Analytics
@@ -45,5 +45,5 @@ The template syntax is [nunjucks](https://www.11ty.dev/docs/languages/nunjucks/)
## References
-- A blog made with the same tools https://github.com/11ty/eleventy-base-blog
-- Eleventy docs https://www.11ty.dev/docs/
+- A blog made with the same tools https://github.com/11ty/eleventy-base-blog
+- Eleventy docs https://www.11ty.dev/docs/
diff --git a/assets/pdf/electronics/readme.md b/assets/pdf/electronics/readme.md
index ed3a22e8f..a2b50ff7c 100644
--- a/assets/pdf/electronics/readme.md
+++ b/assets/pdf/electronics/readme.md
@@ -1,12 +1,12 @@
All the files in this directory were found online
-- practical_electronic_for_inventors.pdf
- - http://instrumentacion.qi.fcen.uba.ar/libro/Scherz.pdf
-- practical_electronics_handbook_sixth_edition.pdf
- - https://electronicsforfun.weebly.com/uploads/1/7/6/5/17652675/practical_electronics_handbook_sixth_edition.pdf
-- a_beginners_guide_to_effect_pedals_components.pdf
- - https://guitarpcb.com/wp-content/uploads/2018/07/A-Beginners-Guide-to-Components.pdf
+- practical_electronic_for_inventors.pdf
+ - http://instrumentacion.qi.fcen.uba.ar/libro/Scherz.pdf
+- practical_electronics_handbook_sixth_edition.pdf
+ - https://electronicsforfun.weebly.com/uploads/1/7/6/5/17652675/practical_electronics_handbook_sixth_edition.pdf
+- a_beginners_guide_to_effect_pedals_components.pdf
+ - https://guitarpcb.com/wp-content/uploads/2018/07/A-Beginners-Guide-to-Components.pdf
Online resources:
-- https://www.electronics-tutorials.ws/
+- https://www.electronics-tutorials.ws/
diff --git a/src/coolcovers/all_along_the_watchtower.md b/src/coolcovers/all_along_the_watchtower.md
index 53ce485a0..89c1bd500 100644
--- a/src/coolcovers/all_along_the_watchtower.md
+++ b/src/coolcovers/all_along_the_watchtower.md
@@ -1,7 +1,7 @@
---
layout: layouts/coolcover.njk
tags: ['coolcovers']
-title: "All along the watchtower - Barbara Keith vs Jimi Hendrix vs Bob Dylan"
+title: 'All along the watchtower - Barbara Keith vs Jimi Hendrix vs Bob Dylan'
---
All along the watchtower is a song written and recorded in 1967 by Bob Dylan when he was spending 18 months recovering from a motorcycle accident. The song has been covered numerous times and the most memorable of these covers is probably the one by the Jimi Hendrix Experience in 68.
@@ -10,7 +10,7 @@ This is a simple 3 verses song narrating a very brief slice of life. A joker and
While Dylan's version is very straightforward with a simple guitar and an harmonica break between the second and third verse, Hendrix version is much more explicit. The guitar breaks and the increasingly excited drums take a more violent take on the unexplained event which is coming. The quick short beats of the drums illustrate a battle or a revolution of some kind.
-Barbara Keith's version is closer to Hendrix's one because it borrows more to the codes of the psychedelic rock from the 60s than to the folk songs of Dylan. I love how the very regular and calm drums of the first two verses illustrate the peaceful walk of our characters heading towards the castle, one can almost picture them on horses calmly walking to an agitated destiny. At the beginning of the third verse the tension grows in a psychedelic explosion worth of the best 60s songs and picturing the agitation in the castle.
+Barbara Keith's version is closer to Hendrix's one because it borrows more to the codes of the psychedelic rock from the 60s than to the folk songs of Dylan. I love how the very regular and calm drums of the first two verses illustrate the peaceful walk of our characters heading towards the castle, one can almost picture them on horses calmly walking to an agitated destiny. At the beginning of the third verse the tension grows in a psychedelic explosion worth of the best 60s songs and picturing the agitation in the castle.
In the third verse the lyrics says "Outside in the distance a wildcat did growl" and a guitar with a wahwah pedal mimics this growl, this is the kind of usage of this pedal which I really like. After this cool third verse a beautiful guitar solo reminds the end of the Hendrix version and the song could have ended right there leaving us with a beautiful rock cover of a classical folk song... But Barbara Keith decided to repeat the third verse again. Was it necessary for the song? No. But that let us appreciate her charming voice for a bit longer and we can't blame her for that.
diff --git a/src/coolcovers/ca_plane_pour_moi.md b/src/coolcovers/ca_plane_pour_moi.md
index 8762facaa..2ba085e95 100644
--- a/src/coolcovers/ca_plane_pour_moi.md
+++ b/src/coolcovers/ca_plane_pour_moi.md
@@ -1,7 +1,7 @@
---
layout: layouts/coolcover.njk
tags: ['coolcovers']
-title: "Ca plane pour moi - The Presidents Of The United States Of America vs. Plastic Bertrand"
+title: 'Ca plane pour moi - The Presidents Of The United States Of America vs. Plastic Bertrand'
---
When an American punk band from the 90s make a cover of an eccentric Belgian punk from the 70s the result is dumb, messy and a ton of fun!
diff --git a/src/coolcovers/california_dreaming.md b/src/coolcovers/california_dreaming.md
index aa5c91b25..175b7f6cc 100644
--- a/src/coolcovers/california_dreaming.md
+++ b/src/coolcovers/california_dreaming.md
@@ -20,4 +20,3 @@ The introduction really translate the melancholic side of the song until the bra
California Dreamin' is one of the songs with the most occurrences in my playlist but I think this version is by far my favorite.
-
diff --git a/src/cv_entries/content/interests.md b/src/cv_entries/content/interests.md
index b896b297d..d5a6852aa 100644
--- a/src/cv_entries/content/interests.md
+++ b/src/cv_entries/content/interests.md
@@ -3,7 +3,7 @@ tags: custom
title: Interests
---
-- Pratique de la guitare seul et en groupe depuis 15 ans.
-- Pratique reguliere du Yoga Vinyasa.
+- Pratique de la guitare seul et en groupe depuis 15 ans.
+- Pratique reguliere du Yoga Vinyasa.
-- TODO: Add side projects
+- TODO: Add side projects
diff --git a/src/cv_entries/content/introduction.md b/src/cv_entries/content/introduction.md
index b6e90a852..a1692a60d 100644
--- a/src/cv_entries/content/introduction.md
+++ b/src/cv_entries/content/introduction.md
@@ -4,4 +4,3 @@ title: About Me
---
Ingénieur logiciel a Paris. Orienté développement serveur et gestion de l'infrastructure selon la philosophie DevOps.
-
diff --git a/src/cv_entries/education/2014_marne_la_valee.md b/src/cv_entries/education/2014_marne_la_valee.md
index 08c0dd5fa..1e44ef968 100644
--- a/src/cv_entries/education/2014_marne_la_valee.md
+++ b/src/cv_entries/education/2014_marne_la_valee.md
@@ -1,6 +1,6 @@
---
-title: "Licence sciences et technologies : mathématiques et informatique"
-organization: "Partenariat Efrei/Université Paris-Est Marne-La-Vallée"
+title: 'Licence sciences et technologies : mathématiques et informatique'
+organization: 'Partenariat Efrei/Université Paris-Est Marne-La-Vallée'
end: 2014-07-01
---
diff --git a/src/cv_entries/work/2015_enablon.md b/src/cv_entries/work/2015_enablon.md
index dee369745..0461b1ae5 100644
--- a/src/cv_entries/work/2015_enablon.md
+++ b/src/cv_entries/work/2015_enablon.md
@@ -1,12 +1,12 @@
---
-title: "Ingénieur Qualité Junior"
+title: 'Ingénieur Qualité Junior'
organization: Enablon
organizationUrl: https://www.linkedin.com/company/enablon/
start: 2015-04-01
end: 2015-09-01
---
-- Développement de tests d’API et de tests d’intégration au sein des applications
-- Etude sur le Framework de test intégré aux applications
-- Analyse et production de code en langage propriétaire Nabsic
-- Echange avec l’équipe de d’Assurance Qualité à Chicago
+- Développement de tests d’API et de tests d’intégration au sein des applications
+- Etude sur le Framework de test intégré aux applications
+- Analyse et production de code en langage propriétaire Nabsic
+- Echange avec l’équipe de d’Assurance Qualité à Chicago
diff --git a/src/cv_entries/work/2016_nexworld.md b/src/cv_entries/work/2016_nexworld.md
index 3e4b3b048..3564cfe46 100644
--- a/src/cv_entries/work/2016_nexworld.md
+++ b/src/cv_entries/work/2016_nexworld.md
@@ -1,5 +1,5 @@
---
-title: "Consultant"
+title: 'Consultant'
organization: Nexworld
organizationUrl: https://nexworld.fr/
start: 2016-02-01
@@ -8,19 +8,19 @@ end: 2019-02-01
Développeur Full Stack, Elis, 2 ans
-- Réalisation et maintenance du système de création de devis et de rémunération des commerciaux Elis.
-- Développement backend Java (Spring/Hibernate/Maven)
-- Développement mobile et frontend (Cordova/AngularJS)
-- Conception et développement d’une application desktop (NW.js/AngularJS)
-- Conception et recette des flux ESB liés aux backends
-- Accompagnement et formation des nouveaux développeurs dans l’équipe
-- Configuration et utilisation d'outils d’intégration continue (Git/Jenkins/Nexus/Sonarr)
-- Administration système (CentOS/tomcat/postgres/docker)
+- Réalisation et maintenance du système de création de devis et de rémunération des commerciaux Elis.
+- Développement backend Java (Spring/Hibernate/Maven)
+- Développement mobile et frontend (Cordova/AngularJS)
+- Conception et développement d’une application desktop (NW.js/AngularJS)
+- Conception et recette des flux ESB liés aux backends
+- Accompagnement et formation des nouveaux développeurs dans l’équipe
+- Configuration et utilisation d'outils d’intégration continue (Git/Jenkins/Nexus/Sonarr)
+- Administration système (CentOS/tomcat/postgres/docker)
Consultant API Management, Sanofi, Engie, Caisse d'épargne, 1 an
-- Installation de CA API Management Gateway et Portail Développeur
-- Développements des expositions de webservices sur des plateformes d’API Management
-- Développements des policies de sécurité et scripts de migration API Management
-- Rédaction des documents d’architectures et d’exploitation (Anglais et Français)
-- Rédaction de guides de bonnes pratiques d'administration et de développement (Anglais et Français)
+- Installation de CA API Management Gateway et Portail Développeur
+- Développements des expositions de webservices sur des plateformes d’API Management
+- Développements des policies de sécurité et scripts de migration API Management
+- Rédaction des documents d’architectures et d’exploitation (Anglais et Français)
+- Rédaction de guides de bonnes pratiques d'administration et de développement (Anglais et Français)
diff --git a/src/cv_entries/work/2019_dashlane.md b/src/cv_entries/work/2019_dashlane.md
index 0f95b6f7a..469b125fc 100644
--- a/src/cv_entries/work/2019_dashlane.md
+++ b/src/cv_entries/work/2019_dashlane.md
@@ -1,5 +1,5 @@
---
-title: "Senior Software Engineer"
+title: 'Senior Software Engineer'
organization: Dashlane
organizationUrl: https://www.dashlane.com/
start: 2019-02-04
@@ -7,25 +7,25 @@ start: 2019-02-04
Server Squad - Développeur et scrum master
-- Migration de notre cluster de monitoring Elasticsearch 5 vers Elasticsearch 7
- - Création des scripts Terraform et Ansible pour créer et déployer les machines
- - Configuration du nouveau cluster Elasticsearch
- - Configuration de l'ingestion des logs vers differents index via logstash
- - Configuration de Kibana pour les différents utilisateurs
- - Gestion de la phase de migration entre les deux clusters
-- Migration de notre BDD MySQL entre deux comptes AWS
- - Création de la nouvelle instance MySQL et de ses security groups via Terraform
- - Création et test de la réplication entre les instances MySQL
- - Test du bon fonctionnement des applications avec la nouvelle BDD
- - Réalisation de la migration, temps d'indisponibilité < 5mn
-- En tant que Scrum Master
- - Présentation de la review aux stackholders a chaque sprint
- - Mise en place de cérémonies régulières (Rétrospectives, refinement, planning)
- - Gestion des priorités des requêtes externes (support utilisateurs, équipes clients, équipe sécurité, ...)
+- Migration de notre cluster de monitoring Elasticsearch 5 vers Elasticsearch 7
+ - Création des scripts Terraform et Ansible pour créer et déployer les machines
+ - Configuration du nouveau cluster Elasticsearch
+ - Configuration de l'ingestion des logs vers differents index via logstash
+ - Configuration de Kibana pour les différents utilisateurs
+ - Gestion de la phase de migration entre les deux clusters
+- Migration de notre BDD MySQL entre deux comptes AWS
+ - Création de la nouvelle instance MySQL et de ses security groups via Terraform
+ - Création et test de la réplication entre les instances MySQL
+ - Test du bon fonctionnement des applications avec la nouvelle BDD
+ - Réalisation de la migration, temps d'indisponibilité < 5mn
+- En tant que Scrum Master
+ - Présentation de la review aux stackholders a chaque sprint
+ - Mise en place de cérémonies régulières (Rétrospectives, refinement, planning)
+ - Gestion des priorités des requêtes externes (support utilisateurs, équipes clients, équipe sécurité, ...)
Mission team "Synchronisation" - Développeur
-- Participation aux spécifications et développement de nouveaux flots d'authentification
-- Analyse de l'architecture existante de la synchronisation et des problèmes de performances
-- Résolution des principaux bugs de la synchronisation pour en améliorer la fiabilité
-- Échanges constants avec les équipes de développeurs clients
+- Participation aux spécifications et développement de nouveaux flots d'authentification
+- Analyse de l'architecture existante de la synchronisation et des problèmes de performances
+- Résolution des principaux bugs de la synchronisation pour en améliorer la fiabilité
+- Échanges constants avec les équipes de développeurs clients
diff --git a/src/guitar/index.md b/src/guitar/index.md
index 04facbdee..e0a6972a7 100644
--- a/src/guitar/index.md
+++ b/src/guitar/index.md
@@ -1,33 +1,32 @@
---
layout: layouts/base.njk
eleventyNavigation:
- key: Guitar
- parent: Music
+ key: Guitar
+ parent: Music
---
## Guitar
I'm using this page to gather resources that I've found useful while learning music. Maybe one day I will organize that properly to make it easier to read for anyone who is not me.
-
### Chords and staffs
- - https://www.hooktheory.com/theorytab
+- https://www.hooktheory.com/theorytab
### Music theory - Scales, Chords, Fretboard...
Scales and chords visualization tools
- - [JGuitar scales, chords, harmonizers](https://jguitar.com/)
- - [Guitar scales - Online Guitar Book](https://onlineguitarbooks.com/guitar-scales/)
- - [The Guitar Grimoire - Adam Kadmon](http://mikesimm.djlemonk.com/bblog/Scales-and-Modes.pdf)
- - [FretFlip](https://fretflip.com/)
- - [Fretbo.ar](https://fretbo.ar/)
- - [muted.io](https://muted.io/)
- - [Triads visualizations](https://triadmapper.herokuapp.com/)
- - [All chords diagrams](https://images.template.net/wp-content/uploads/2016/05/05072432/PDF-Document-for-Suspended-Guitar-Chord-Templates.pdf)
- - [Keyboard scales](https://www.pianoscales.org/)
+- [JGuitar scales, chords, harmonizers](https://jguitar.com/)
+- [Guitar scales - Online Guitar Book](https://onlineguitarbooks.com/guitar-scales/)
+- [The Guitar Grimoire - Adam Kadmon](http://mikesimm.djlemonk.com/bblog/Scales-and-Modes.pdf)
+- [FretFlip](https://fretflip.com/)
+- [Fretbo.ar](https://fretbo.ar/)
+- [muted.io](https://muted.io/)
+- [Triads visualizations](https://triadmapper.herokuapp.com/)
+- [All chords diagrams](https://images.template.net/wp-content/uploads/2016/05/05072432/PDF-Document-for-Suspended-Guitar-Chord-Templates.pdf)
+- [Keyboard scales](https://www.pianoscales.org/)
@@ -35,6 +34,7 @@ I'm using this page to gather resources that I've found useful while learning mu


+
@@ -46,14 +46,15 @@ Position III 
Position IV-2 
Position V 
+
CAGED system
[Pick up music - The CAGED system explained](https://www.youtube.com/watch?v=-nphFK6HFjY)
-
+
Learning to read a staff
@@ -63,6 +64,7 @@ Position V 
Mnemonic in French:
+
aMIs SOLdats CI-REz FAcilement vos bottes
FAit LADOrMIr
@@ -73,19 +75,17 @@ Guitar open string on the staff:
-
iOS applications
- - [Solfa](https://apps.apple.com/us/app/solfa-learn-musical-notes/id1436741307) Learning to read notes
- - [Hearing](https://apps.apple.com/us/app/hearing-ear-training-piano/id1474241582) Learning to identify notes by hear
+- [Solfa](https://apps.apple.com/us/app/solfa-learn-musical-notes/id1436741307) Learning to read notes
+- [Hearing](https://apps.apple.com/us/app/hearing-ear-training-piano/id1474241582) Learning to identify notes by hear
-
-
### Chords progressions and licks
#### Common chord progressions
+
Common chords progressions
@@ -101,6 +101,7 @@ G13 - 3x344x
Cmin7 - x3534x
Cmin9 - x3133x
```
+
@@ -125,6 +126,7 @@ Gmin9 - x 10 8 10 10 x
Ebmaj7 - x 6 8 7 8 6
Ebmin7 - x 6 8 6 7 6
```
+
@@ -135,6 +137,7 @@ C#min7 - x46454
G#min7 - 4x444x
F#min7 - x24222
```
+
#### Blues
diff --git a/src/music/index.md b/src/music/index.md
index d98d3af46..b58fff5af 100644
--- a/src/music/index.md
+++ b/src/music/index.md
@@ -1,8 +1,8 @@
---
layout: layouts/base.njk
eleventyNavigation:
- key: Music
- order: 5
+ key: Music
+ order: 5
CSSFile: 'css/pages/music.css'
---
@@ -14,11 +14,11 @@ When I'm coding I listen to music and when I'm not coding I try to play some mus
A list of useful apps I created for my music playing:
-- [Song Book](https://apps.statox.fr/songbook) A list of song chords I took from the internet or made by myself and like to play
-- [Metronome](https://apps.statox.fr/metronome) A metrone which works just as I want
-- [Tap Tempo](https://apps.statox.fr/taptempo) A Tap Tempo app
-- [Chord wheel](https://apps.statox.fr/chordwheel) The online implementation of a book by [Jim Flesser](https://chordwheel.com/)
-- [Scales visualizer and chords progressions](https://apps.statox.fr/scales) A tool I made to learn scale degrees
+- [Song Book](https://apps.statox.fr/songbook) A list of song chords I took from the internet or made by myself and like to play
+- [Metronome](https://apps.statox.fr/metronome) A metrone which works just as I want
+- [Tap Tempo](https://apps.statox.fr/taptempo) A Tap Tempo app
+- [Chord wheel](https://apps.statox.fr/chordwheel) The online implementation of a book by [Jim Flesser](https://chordwheel.com/)
+- [Scales visualizer and chords progressions](https://apps.statox.fr/scales) A tool I made to learn scale degrees
### [Production](https://soundcloud.com/statox/tracks)
@@ -43,4 +43,3 @@ The user manuals for my gear as well as some PDF documents about music and elect
One of my weird obsession is cover songs. I try to write a bit about my discoveries.
[Cool covers page](/coolcovers/)
-
diff --git a/src/pages/about.md b/src/pages/about.md
index bfa126c61..c4ca9aa4b 100644
--- a/src/pages/about.md
+++ b/src/pages/about.md
@@ -1,11 +1,11 @@
---
layout: layouts/base.njk
title: About
-permalink: "/about/"
-CSSFile: "css/pages/about.css"
+permalink: '/about/'
+CSSFile: 'css/pages/about.css'
eleventyNavigation:
- key: About
- order: 6
+ key: About
+ order: 6
---
### Hello
@@ -20,9 +20,9 @@ This website is just a place for me to talk a bit about my side projects and kee
You can email me at me AT statox DOT fr or reach out to me on any of these social platforms:
-- [Github](https://github.com/statox/) - Where I host my side projects and experiments.
-- [vi.stackexchange](https://vi.stackexchange.com/users/1841/statox) - Where I've been a moderator for a few years and try to be helpful to other Vim users.
-- [Linked in](https://www.linkedin.com/in/adrien-fabre-7a30994b/) - Where you can contact me if you want to.
+- [Github](https://github.com/statox/) - Where I host my side projects and experiments.
+- [vi.stackexchange](https://vi.stackexchange.com/users/1841/statox) - Where I've been a moderator for a few years and try to be helpful to other Vim users.
+- [Linked in](https://www.linkedin.com/in/adrien-fabre-7a30994b/) - Where you can contact me if you want to.
### Technology on this site
diff --git a/src/pages/apps.md b/src/pages/apps.md
index 675525ba3..63b84dbbd 100644
--- a/src/pages/apps.md
+++ b/src/pages/apps.md
@@ -1,10 +1,10 @@
---
layout: layouts/base.njk
title: Apps
-permalink: "/apps/"
+permalink: '/apps/'
eleventyNavigation:
- key: Apps
- order: 4
+ key: Apps
+ order: 4
---
## Stuff I use
@@ -14,4 +14,3 @@ At one point I got limited by the fact that this blog is statically generated an
So I setup [apps.statox.fr](https://apps.statox.fr) which is a collection of web app powered by [SvelteJS](https://svelte.dev/) I made for my own use. They are probably not useful to any one else than me but have a look you might find something interesting.
For example this blog used to have a `/notes` page which I used to take notes of various commands and code snippets I found convenient to have available, this page now lives [here](https://apps.statox.fr/notes). I also moved [my songbook](https://apps.statox.fr/songbook) over there and I keep this collection of apps growing.
-
diff --git a/src/pages/ring.md b/src/pages/ring.md
index 459253b25..a802ba869 100644
--- a/src/pages/ring.md
+++ b/src/pages/ring.md
@@ -1,25 +1,25 @@
---
layout: layouts/base.njk
title: Ring
-permalink: "/ring/"
+permalink: '/ring/'
eleventyNavigation:
- key: Ring
- order: 7
+ key: Ring
+ order: 7
---
### Stuff to share
Some blogs and personal websites I like to read regularly (or just every once in a while) and sometimes use as an inspiration for some features on this site:
-- https://25.wf
-- https://arp242.net
-- https://benknoble.github.io
-- https://www.galaxykate.com/
-- https://jvns.ca
-- https://kevq.uk/
-- https://nicolas-hoizey.com
-- http://rachelbythebay.com/w/
-- https://sericaia.me
-- https://tonycodes.com
-- https://tonsky.me/
-- https://uglyduck.ca/
+- https://25.wf
+- https://arp242.net
+- https://benknoble.github.io
+- https://www.galaxykate.com/
+- https://jvns.ca
+- https://kevq.uk/
+- https://nicolas-hoizey.com
+- http://rachelbythebay.com/w/
+- https://sericaia.me
+- https://tonycodes.com
+- https://tonsky.me/
+- https://uglyduck.ca/
diff --git a/src/pedals/index.md b/src/pedals/index.md
index 4a6236c4d..de8aba9d2 100644
--- a/src/pedals/index.md
+++ b/src/pedals/index.md
@@ -1,8 +1,8 @@
---
layout: layouts/base.njk
eleventyNavigation:
- key: Pedals
- parent: Music
+ key: Pedals
+ parent: Music
---
## Pedals
@@ -11,43 +11,43 @@ A work in progress list of resources for the effect pedals I use in my pedalboar


+
A picture of my pedalboard as of January 2024.
Some stats:
-- 20 Jack SquarePlug SP400 Mono hand-soldered by me
-- ~2m50 of patch cable
-- ~4m of velcro tape
-- ~5m of pre-made black electric cable
-- ~1m50 of transparent electric cable hand-soldered by me to power the OC-3, BO100, Dark Mouse and Instant Lofi Junky in parallel from one 100mA output
+- 20 Jack SquarePlug SP400 Mono hand-soldered by me
+- ~2m50 of patch cable
+- ~4m of velcro tape
+- ~5m of pre-made black electric cable
+- ~1m50 of transparent electric cable hand-soldered by me to power the OC-3, BO100, Dark Mouse and Instant Lofi Junky in parallel from one 100mA output
The power supply is a [Donner DP-2](https://fr.audiofanzine.com/alimentation-pedale/donner/dp-2-power-supply/) I can't find a lot of references to it online but I'm quite happy with it: It is very quiet and just does the job.
-
Signal chain:
-| Brand | Model | Description | Manual
-|-------|-------|-------------|-------
-| Peterson | Strobostomp HD | Tuner and mute button | [Peterson](https://www.petersontuners.com/media/pdf/StroboStomp_HD_Manual_v1.1_EN.pdf) (_[mirror](/pdf/pedal_user_manuals/StroboStomp_HD_Manual_v1.1_EN.pdf)_)
-| Boss | OC-3 | Octaver. Bass and low synth sounds | [Roland](https://static.roland.com/assets/media/pdf/OC-3_e01_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_oc3_user_manual.pdf)_)
-| Behringer | BO100 | Overdrive. "not a clone" of the Boss BD-2. Overall light overdrive to add some sustain and space. | [Behringer](https://mediadl.musictribe.com/media/sys_master/hed/h3f/8850084069406.pdf) (_[mirror](/pdf/pedal_user_manuals/behringer_bo100_user_manual.pdf)_)
-| Donner | Dark Mouse | Op. Amp distortion. Two modes from overdrive to heavy distortion | [Donner](https://cdn.shopify.com/s/files/1/1384/9629/files/EC1178_Dark_Mouse__Manual_V02_190809.pdf?v=1597289663) (_[mirror](/pdf/pedal_user_manuals/donner_dark_mouse_manual.pdf)_)
-| ZVEX | Instant Lofi Junky | Vibrato+Compressor. Lofi vibe mixing vibrato, chorus-y sounds with a compressor. | [ZVEX](https://static1.squarespace.com/static/555e332ce4b0577e788c3a16/t/559efae5e4b0da93269a9ffb/1436482277079/ZVEX+Instant+Lo-Fi+Junky+Instructions.pdf) (_[mirror](/pdf/pedal_user_manuals/zvex_instant_lofi_junky_user_manual.pdf)_)
-| Boss | CH-1 | Chorus. I haven't found a good way to incorporate it to my sound yet but it's fun to use once in a while | [Roland](https://static.roland.com/assets/media/pdf/CH-1_M_eng03_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_ch1_user_manual.pdf)_)
-| Electro-Harmonix | Canyon | Delay. A very complete delay pedal from classic delay, to tape and modulation delays. The shimmer mode give a nice wide reverb and the octave mode plays amazingly with the EQD Afterneath | [EHX](https://www.ehx.com/wp-content/uploads/2021/01/canyon-manual.pdf) (_[mirror](/pdf/pedal_user_manuals/ehx_canyon_manual.pdf)_)
-| EarthQuaker Devices | Afterneath | A crazy reverb pedal. It's quite hard to describe but creates crazy ambient sounds which reverberate to the infinity. The user manual is worth a read, it approaches the pedal as a role playing game | [EQD](https://static1.squarespace.com/static/57cebe2c03596e075fca5f24/t/656fc46102d950061c2b9d06/1701823585949/EQD-Afterneath-Manual-R2-WEB.pdf) (_[mirror](/pdf/pedal_user_manuals/eqd_afterneath_manual.pdf)_)
-| ToneCity | Tiny Spring | A discreet reverb. Always on to add some space to the sound | [device.report](https://device.report/m/2a2f8a0f7cf833579a89c3817b61a29cd74144e0d5414496ffd212cabed59c0c_optim.pdf) (_[mirror](/pdf/pedal_user_manuals/tonecity_tinyspring_manual.jpg)_)
-| Boss | RC-3 | Loop station with "start record on play", tap tempo and a drum machine | [Roland](https://static.roland.com/assets/media/pdf/RC-3_eng03_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_rc3_user_manual.pdf)_)
-| Boss | RC-10r | Loop station with two parts loop and larger drums than the RC-3 | [Owner's manual](https://static.roland.com/assets/media/pdf/RC-10R_eng03_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_rc10r_user_manual.pdf)_) / [Parameter guide](https://static.roland.com/assets/media/pdf/RC-10R_parameter_eng01_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_rc10r_parameter_guide.pdf)_)
+| Brand | Model | Description | Manual |
+| ------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| Peterson | Strobostomp HD | Tuner and mute button | [Peterson](https://www.petersontuners.com/media/pdf/StroboStomp_HD_Manual_v1.1_EN.pdf) (_[mirror](/pdf/pedal_user_manuals/StroboStomp_HD_Manual_v1.1_EN.pdf)_) |
+| Boss | OC-3 | Octaver. Bass and low synth sounds | [Roland](https://static.roland.com/assets/media/pdf/OC-3_e01_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_oc3_user_manual.pdf)_) |
+| Behringer | BO100 | Overdrive. "not a clone" of the Boss BD-2. Overall light overdrive to add some sustain and space. | [Behringer](https://mediadl.musictribe.com/media/sys_master/hed/h3f/8850084069406.pdf) (_[mirror](/pdf/pedal_user_manuals/behringer_bo100_user_manual.pdf)_) |
+| Donner | Dark Mouse | Op. Amp distortion. Two modes from overdrive to heavy distortion | [Donner](https://cdn.shopify.com/s/files/1/1384/9629/files/EC1178_Dark_Mouse__Manual_V02_190809.pdf?v=1597289663) (_[mirror](/pdf/pedal_user_manuals/donner_dark_mouse_manual.pdf)_) |
+| ZVEX | Instant Lofi Junky | Vibrato+Compressor. Lofi vibe mixing vibrato, chorus-y sounds with a compressor. | [ZVEX](https://static1.squarespace.com/static/555e332ce4b0577e788c3a16/t/559efae5e4b0da93269a9ffb/1436482277079/ZVEX+Instant+Lo-Fi+Junky+Instructions.pdf) (_[mirror](/pdf/pedal_user_manuals/zvex_instant_lofi_junky_user_manual.pdf)_) |
+| Boss | CH-1 | Chorus. I haven't found a good way to incorporate it to my sound yet but it's fun to use once in a while | [Roland](https://static.roland.com/assets/media/pdf/CH-1_M_eng03_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_ch1_user_manual.pdf)_) |
+| Electro-Harmonix | Canyon | Delay. A very complete delay pedal from classic delay, to tape and modulation delays. The shimmer mode give a nice wide reverb and the octave mode plays amazingly with the EQD Afterneath | [EHX](https://www.ehx.com/wp-content/uploads/2021/01/canyon-manual.pdf) (_[mirror](/pdf/pedal_user_manuals/ehx_canyon_manual.pdf)_) |
+| EarthQuaker Devices | Afterneath | A crazy reverb pedal. It's quite hard to describe but creates crazy ambient sounds which reverberate to the infinity. The user manual is worth a read, it approaches the pedal as a role playing game | [EQD](https://static1.squarespace.com/static/57cebe2c03596e075fca5f24/t/656fc46102d950061c2b9d06/1701823585949/EQD-Afterneath-Manual-R2-WEB.pdf) (_[mirror](/pdf/pedal_user_manuals/eqd_afterneath_manual.pdf)_) |
+| ToneCity | Tiny Spring | A discreet reverb. Always on to add some space to the sound | [device.report](https://device.report/m/2a2f8a0f7cf833579a89c3817b61a29cd74144e0d5414496ffd212cabed59c0c_optim.pdf) (_[mirror](/pdf/pedal_user_manuals/tonecity_tinyspring_manual.jpg)_) |
+| Boss | RC-3 | Loop station with "start record on play", tap tempo and a drum machine | [Roland](https://static.roland.com/assets/media/pdf/RC-3_eng03_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_rc3_user_manual.pdf)_) |
+| Boss | RC-10r | Loop station with two parts loop and larger drums than the RC-3 | [Owner's manual](https://static.roland.com/assets/media/pdf/RC-10R_eng03_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_rc10r_user_manual.pdf)_) / [Parameter guide](https://static.roland.com/assets/media/pdf/RC-10R_parameter_eng01_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_rc10r_parameter_guide.pdf)_) |

+
A picture of my pedalboard as of February 2022.
-
### Sample settings
#### Boss BD-2 (similar to Behringer BO100)
@@ -70,15 +70,14 @@ _TODO: Turn that into images and come up with my own sample settings. Current se
**Brighter Chorus with commpressed signal**
-- Volume: 60%
-- Speed: 60%
-- Comp/Lofi: 40%
-- Tone: 100%
-- Depth: 60%
+- Volume: 60%
+- Speed: 60%
+- Comp/Lofi: 40%
+- Tone: 100%
+- Depth: 60%
Important part here is the `Tone` pot. Up: Let high cuts through. Down: Mellow things out.
-
### Users manuals
See my [user manuals](/user_manuals/) page.
diff --git a/src/posts/2017/02/GOD_vim.md b/src/posts/2017/02/GOD_vim.md
index 832157a80..d8b144915 100644
--- a/src/posts/2017/02/GOD_vim.md
+++ b/src/posts/2017/02/GOD_vim.md
@@ -14,40 +14,43 @@ When I write an answer I always try to think about how I can not only help the u
Indeed Vim has an amazing built-in help system accessible directly from the editor itself using the command `:h`. So whenever I write my answers I do my best to add the relevant help topics. And I also like to add a link to one of the several online version of the help
- - http://vimdoc.sourceforge.net/ That I used at first but the anchoring of the topics were not always deterministic so it was to practical to use.
- - https://vimhelp.org/ Which I currently use.
- - And even https://neovim.io/doc for neovim users.
+- http://vimdoc.sourceforge.net/ That I used at first but the anchoring of the topics were not always deterministic so it was to practical to use.
+- https://vimhelp.org/ Which I currently use.
+- And even https://neovim.io/doc for neovim users.
### But it's painful
+
For a long time I just wrote the help command like `:h autocmd-events` in my answers but this was not convenient:
- - First I have to do my own research in the help system, like any vimmer would do.
- - Then I have to copy the help topic to my clipboard
- - In the web interface I have to redundantly type the string `:h` and add the help topic.
- - Then because I think new users are more inclined to read the doc if it is available right under their hand I look for the topic on an online version of the help
- - Finally I can update my markdown with the right link
+- First I have to do my own research in the help system, like any vimmer would do.
+- Then I have to copy the help topic to my clipboard
+- In the web interface I have to redundantly type the string `:h` and add the help topic.
+- Then because I think new users are more inclined to read the doc if it is available right under their hand I look for the topic on an online version of the help
+- Finally I can update my markdown with the right link
After doing that for a few months and feeling the pain I started creating a short hack in my `.vimrc` to improve this workflow, until the day I read [How can I quickly convert a Vim help tag to a vimhelp.appspot.com link?](https://vi.stackexchange.com/q/4346/1841). This question confirmed that this action was a pain point for other people and that pushed me to create a proper plugin.
### So let's create a plugin!
+
So I created [GOD.vim](https://github.com/statox/GOD.vim) this is a very simple plugin which goal is to easily get a markdown expression describing a help topic and linking to its online version. The plugin does the following:
- - Create a new command `:GOD` which takes the exact same parameter as `:h`. The autcomplete behavior is completely duplicated thanks to [`:h :command-nargs`](http://vimhelp.appspot.com/map.txt.html#%3Acommand-nargs) and [`:h :command-complete`](http://vimhelp.appspot.com/map.txt.html#%3Acommand-complete), see [how I create the command](https://github.com/statox/GOD.vim/blob/bed2a6fe9458284760d6fb5f08495e6579ce69dd/plugin/GOD.vim#L16):
- ``` vim
- command! -nargs=+ -complete=help GOD call GOD#GetOnlineDoc('vimhelp', )
- ```
- - Open the corresponding help page, parse the help topics under the cursor and get the first one.
- - Use this string to build a URL to the relevant help website.
- - Use this URL to generate a markdown template of the form `[:h help-topic](https://url-of-the-help.com/escaped-help-topic)`
- - Copy this template to the clipboard.
+- Create a new command `:GOD` which takes the exact same parameter as `:h`. The autcomplete behavior is completely duplicated thanks to [`:h :command-nargs`](http://vimhelp.appspot.com/map.txt.html#%3Acommand-nargs) and [`:h :command-complete`](http://vimhelp.appspot.com/map.txt.html#%3Acommand-complete), see [how I create the command](https://github.com/statox/GOD.vim/blob/bed2a6fe9458284760d6fb5f08495e6579ce69dd/plugin/GOD.vim#L16):
+ ```vim
+ command! -nargs=+ -complete=help GOD call GOD#GetOnlineDoc('vimhelp', )
+ ```
+- Open the corresponding help page, parse the help topics under the cursor and get the first one.
+- Use this string to build a URL to the relevant help website.
+- Use this URL to generate a markdown template of the form `[:h help-topic](https://url-of-the-help.com/escaped-help-topic)`
+- Copy this template to the clipboard.
I also added some additional features:
- - Being able to link either to the vim help or the neovim help using respectively `:GOD` and `:NGOD`
- - Being able to have a nicely formatted markdown list if several help topics are given as parameters to the command.
+
+- Being able to link either to the vim help or the neovim help using respectively `:GOD` and `:NGOD`
+- Being able to have a nicely formatted markdown list if several help topics are given as parameters to the command.
I think the trickiest part about writing this plugin was to create a pure vimscript encoding function to handle the URLs. Indeed a lot of help topics have some characters which need to be URL encoded. The first version of my encoding function didn't work very well but fortunately I got the help of great developers from the [vi.stackexchange](https://vi.stackexchange.com) community, namely [Luc Hermitte](https://luchermitte.github.io/) and [Martin Tournoij](https://www.arp242.net/) who helped me with different parts of this plugin and in particular who helped me coming up with this function:
-``` vim
+```vim
" Encode url
function! s:URLEncode(str) abort
" Replace each non hex character of the string by its hex representation
@@ -59,8 +62,8 @@ It takes an help topic as a parameter like `/\@<=`, iterates on each characters
Here `printf()` is used with the following format: `%%%02x`:
- - `%%` is used to insert a litteral `%` character (which is used in URL encoding to specify encoded characters)
- - `%02x` is used to get the hex value of the character. `02` is the number of `0` to use for the padding.
+- `%%` is used to insert a litteral `%` character (which is used in URL encoding to specify encoded characters)
+- `%02x` is used to get the hex value of the character. `02` is the number of `0` to use for the padding.
With our example topic `/\@<=` the function returns `%2f%5c%40%3c%3d`.
diff --git a/src/posts/2017/09/vim_colorscheme_changer.md b/src/posts/2017/09/vim_colorscheme_changer.md
index 699986484..532e1a3d9 100644
--- a/src/posts/2017/09/vim_colorscheme_changer.md
+++ b/src/posts/2017/09/vim_colorscheme_changer.md
@@ -14,8 +14,8 @@ In a world where Apple has a tool by default on most of its devices to change th
To add this feature I made a very simple plugin which takes for variables as its configuration:
-- `g:dayTime` and `g:nightTime` which are two arrays used to describe when in the plugin should switch the colorscheme in the morning and in the evening.
-- `g:dayColorscheme` and `g:nightColorscheme` which are the names of the colorschemes to use for each time of the day.
+- `g:dayTime` and `g:nightTime` which are two arrays used to describe when in the plugin should switch the colorscheme in the morning and in the evening.
+- `g:dayColorscheme` and `g:nightColorscheme` which are the names of the colorschemes to use for each time of the day.
The source code is on [Github](https://github.com/statox/colorscheme-changer.vim).
@@ -27,7 +27,7 @@ This was interesting to create this plugin because I didn't have an opportunity
I noticed that my main pain point related to my colorscheme was when I switch vim to the diff mode using [`:h :diffthis`](http://vimhelp.appspot.com/diff.txt.html#%3Adiffthis). I realized that my current colorscheme didn't do as well as the previous one in diff mode. So I came up with a pretty simple trick in my `.vimrc`:
-``` vim
+```vim
" Color configuration
try
" Define the default colorscheme and the one used in diff mode
@@ -47,7 +47,7 @@ I noticed that my main pain point related to my colorscheme was when I switch vi
The idea is very simple: Declare two variables holding the names of the colorschemes I want to use in normal mode and in diff mode and define some wrapper commands around diffmode:
- - `:DT` (For `DiffThis`) will change the colorscheme and then switch every window to diffmode
- - `:DO` (For `DiffOff`) will do the opposite: Switch back to default colorscheme and stop diff mode.
+- `:DT` (For `DiffThis`) will change the colorscheme and then switch every window to diffmode
+- `:DO` (For `DiffOff`) will do the opposite: Switch back to default colorscheme and stop diff mode.
These lines having been [in my `.vimrc`](https://github.com/statox/dotfiles/blob/7fd57caab6f7e610529b976ec45728c650a1322b/vimrc#L381-L403) for a few time now and so far they fit my needs. Maybe in the future I'll also explain with more details how I handle the diff mode in Vim.
diff --git a/src/posts/2019/01/p5-pool.md b/src/posts/2019/01/p5-pool.md
index 5e7f847f8..a92cb2d43 100644
--- a/src/posts/2019/01/p5-pool.md
+++ b/src/posts/2019/01/p5-pool.md
@@ -24,13 +24,13 @@ What do I need to do that?
First of all I need a table and some balls rolling on it. This is pretty straightforward: a p5.js canvas will be my table, my balls are simple javascript objects with some coordinates, the ability to apply a force on it (i.e. incrementing the coordinates), a friction force to keep the ball from rolling forever and some tests to prevent the balls from falling out of the table.
-``` js
+```js
function Ball(x, y, id, color) {
this.pos = new p5.Vector(x, y);
this.vel = new p5.Vector(0, 0);
this.r = 10;
- this.move = function() {
+ this.move = function () {
// Add friction
var coefficientOfFriction = 0.99;
this.vel.mult(coefficientOfFriction);
@@ -41,12 +41,12 @@ function Ball(x, y, id, color) {
// Check the limits
if (this.pos.x - this.r < 0 || this.pos.x + this.r > W - this.r) {
- this.vel.x *= - coefficientOfFriction;
+ this.vel.x *= -coefficientOfFriction;
}
if (this.pos.y - this.r < 0 || this.pos.y + this.r > L - this.r) {
- this.vel.y *= - coefficientOfFriction;
+ this.vel.y *= -coefficientOfFriction;
}
- }
+ };
}
```
@@ -54,8 +54,8 @@ Easy, right? With that I can apply a force to a ball (as it's velocity) and way
Let's add to that a simple function to know if a ball is colliding with another one. To do that we can simply check the distance between two balls is larger than the sum of the balls radius. I came up with something quick and dirty, but mostly dirty. Here I knew I wanted to tag all the balls part of a collision:
-``` js
-this.isColliding = function(otherBall) {
+```js
+this.isColliding = function (otherBall) {
// Get the distance between the center of the two balls
var dx = otherBall.pos.x - this.pos.x;
var dy = otherBall.pos.y - this.pos.y;
@@ -69,7 +69,7 @@ this.isColliding = function(otherBall) {
return true;
}
return false;
-}
+};
```
Having this code I was able to create my pool, put balls on it, apply a force on them and change their color when they hit each other. That is cool... But now what?
diff --git a/src/posts/2020/01/p5-genetic-algorithms.md b/src/posts/2020/01/p5-genetic-algorithms.md
index df5d64e1f..8033360cf 100644
--- a/src/posts/2020/01/p5-genetic-algorithms.md
+++ b/src/posts/2020/01/p5-genetic-algorithms.md
@@ -12,7 +12,7 @@ And [the code](https://github.com/statox/p5-genetics) is on Github, it's not bea
### Teaching a machine to do stuff
-Once of the funniest things to do with a computer or a piece of hardware and is to make it smart. This has been humankind obsession for many decades now and it's not going to stop anytime soon. Of course there are tons of way to make a piece of silicon smart, but for this project I wanted to explore a very simple category of machine learning algorithms: *The genetic algorithms*.
+Once of the funniest things to do with a computer or a piece of hardware and is to make it smart. This has been humankind obsession for many decades now and it's not going to stop anytime soon. Of course there are tons of way to make a piece of silicon smart, but for this project I wanted to explore a very simple category of machine learning algorithms: _The genetic algorithms_.
Basically the way genetic algorithms works is the following: You take a bunch of things that you want to make smart, you make them accomplish a task in a random way and you score each of them depending on how well they succeeded at the task. Once they are all done you eliminate the worst ones and you keep the ones which did best. You will then slightly change the remaining ones and make them run the task again. The theory says that your new generation of things should do a bit better than the previous generation. Rinse, repeat and boom after a few generation you have a bunch of things pretty good at doing this one thing you asked them to do.
@@ -20,7 +20,7 @@ I love the idea of these algorithms because it is quite simple to understand and
### I want to make a smart robot
-So first thing first, I need to create a robot... Here I will make the simplest robot ever: it will be *a square*! All it needs is a position (i.e. a 2 dimensional vector) and a way to change this position. Here is the time to introduce the concept of genes:
+So first thing first, I need to create a robot... Here I will make the simplest robot ever: it will be _a square_! All it needs is a position (i.e. a 2 dimensional vector) and a way to change this position. Here is the time to introduce the concept of genes:
I am creating a genetic algorithm, so it makes sense that at some point some genes are involved, right? Here the genes of a robot will be the pattern it will follow: This is actually a succession of order saying "Go up" or "Go left" or basically "Move of one position in one of the two dimensions of your plan". Every robot will be created with an array of genes and its life will be devoted to following these instructions.
@@ -28,7 +28,7 @@ My robot will also use some additional properties. I will store its initial posi
So here is my simple robot:
-``` js
+```js
function Robot(x, y, r, lifespan) {
this.initX = x;
this.initY = y;
@@ -40,16 +40,16 @@ function Robot(x, y, r, lifespan) {
this.genes = new Genes(this.lifespan);
}
-Robot.prototype.show = function() {
+Robot.prototype.show = function () {
if (this.crashed) {
- fill(200, 0, 0)
+ fill(200, 0, 0);
} else if (this.foundTarget) {
- fill(0, 200, 0)
+ fill(0, 200, 0);
} else {
- fill(0, 0, 200)
+ fill(0, 0, 200);
}
rect(this.pos.x, this.pos.y, this.r, this.r);
-}
+};
```
Let's notice that it changes its color depending on if it crashed (i.e touched the border of the frame) or if it reached the target. These calculations are made when the robot moves.
@@ -58,13 +58,13 @@ Let's notice that it changes its color depending on if it crashed (i.e touched t
So having a robot and making it move is good but to create a genetic algorithm I need to use more bots. So I will need to create a crowd of robots all starting at the same position but all with different genes (and that makes each robot unique and beautiful, just like you 🤗):
-``` js
+```js
function Crowd(size) {
this.robots = [];
this.matingPool = [];
this.size = size;
- for (var i=0; i In geometry, circle packing is the study of the arrangement of circles (of equal or varying sizes) on a given surface such that no overlapping occurs and so that no circle can be enlarged without creating an overlap.
+> In geometry, circle packing is the study of the arrangement of circles (of equal or varying sizes) on a given surface such that no overlapping occurs and so that no circle can be enlarged without creating an overlap.
And to quote [the same source](https://en.wikipedia.org/wiki/Kitten)
@@ -26,17 +26,12 @@ And to quote [the same source](https://en.wikipedia.org/wiki/Kitten)
So for this project I wanted to use some really cute pictures and duplicate them with a bunch of non overlapping circles.
-
### Loading the pictures
Before packing circles on these cuties we first need to load the images in our p5.js sketch. To do so I created a `reset()` function which will be used each time I need a new image. It's goal is to get the color of each pixels on the image so that we can use the color later on:
-``` js
-const IMAGES = [
- 'data/kitten1.png',
- 'data/kitten2.jpg',
- 'data/kitten3.jpg'
-];
+```js
+const IMAGES = ['data/kitten1.png', 'data/kitten2.jpg', 'data/kitten3.jpg'];
function reset() {
// Stop calling draw() while we load the picture otherwise we break everything
@@ -57,13 +52,13 @@ function reset() {
img.loadPixels();
let d = img.pixels.length;
- for (let i = 0; i < d; i+=4) {
+ for (let i = 0; i < d; i += 4) {
r = img.pixels[i];
- g = img.pixels[i+1];
- b = img.pixels[i+2];
- a = img.pixels[i+3];
+ g = img.pixels[i + 1];
+ b = img.pixels[i + 2];
+ a = img.pixels[i + 3];
- imgColors.push(color(r, g, b, a))
+ imgColors.push(color(r, g, b, a));
}
// Start the packing again!
@@ -82,13 +77,13 @@ Once we looped through all these values we have an array `imgColors` containing
Before we pack the image with circles we need to generate one of them. Here our goal is the following: Return a new circle which does not overlap the others or return nothing (we will handle the failed generations later). So far the algorithm is not very complex: We have a list of existing circles `circles` (Empty at the beginning), we generate a random position `(x, y)` and a radius `r`, we then iterate on the list of existing circles and test if its distance to the newly generated one is larger than the sum of their radius (i.e. they don't overlap).
-``` js
+```js
function newCircle() {
let x = random(img.width);
let y = random(img.height);
let r = random(MAX_INITIAL_SIZE);
- const intersection = circles.findIndex(other => {
+ const intersection = circles.findIndex((other) => {
if (dist(x, y, other.x, other.y) < other.r + r) {
return true;
}
@@ -106,7 +101,7 @@ function newCircle() {
Now that we can generate one circle let's make a function which tries to generate a given amount of circles so that one iteration will see several ones created:
-``` js
+```js
function newCircles() {
let totalNewCircles = NEW_CIRCLES_BY_ITERATION;
let remainingAttemps = NEW_CIRCLES_ATTEMPTS;
diff --git a/src/posts/2020/07/comments.md b/src/posts/2020/07/comments.md
index 3e61bd95e..16ab66840 100644
--- a/src/posts/2020/07/comments.md
+++ b/src/posts/2020/07/comments.md
@@ -16,12 +16,12 @@ The full source of the script is included in the site repository [here](https://
Here are the important steps to make all of this working:
- - Create a dedicated repo [blog-comments](https://github.com/statox/blog-comments/issues) which will contain the issues used to host comments;
- - Have the CI run the script each time a new article is published;
- - Give the script the ability to create new issues in the blog-comments repo;
- - Give each post a unique number representing the issue ID on Github. [Eleventy](https://www.11ty.dev/docs/data-cascade/) provides a simple way to do that;
- - Make the script parsing all the published posts, listing the posts without an associated issue and creating the issues;
- - Change the posts source code to inject the comments.
+- Create a dedicated repo [blog-comments](https://github.com/statox/blog-comments/issues) which will contain the issues used to host comments;
+- Have the CI run the script each time a new article is published;
+- Give the script the ability to create new issues in the blog-comments repo;
+- Give each post a unique number representing the issue ID on Github. [Eleventy](https://www.11ty.dev/docs/data-cascade/) provides a simple way to do that;
+- Make the script parsing all the published posts, listing the posts without an associated issue and creating the issues;
+- Change the posts source code to inject the comments.
### A quick update
@@ -37,16 +37,16 @@ _February 2022 -_ I just found out about [utteranc.es](https://utteranc.es/) whi
Running a script at build time with travis-ci is fairly straight forward. I added a new step in the `script` job looking like this:
-``` yaml
+```yaml
script:
- - npm run create-issues -- $BASIC_AUTH_HEADER
+ - npm run create-issues -- $BASIC_AUTH_HEADER
```
`$BASIC_AUTH_HEADER` is a variable which contains the string `github_username:github_password` encoded in base64. It will be used by the script to authenticate its calls to the Github API [using Basic Authentication](https://developer.github.com/v3/#authentication). Travis has [a simple interface](https://docs.travis-ci.com/user/environment-variables/#defining-variables-in-repository-settings) to define this kind of variable. The double dash `--` is used to give a parameter to a npm script defined in `package.json`.
In `package.json` I added a new script like this:
-``` json
+```json
"scripts": {
"create-issues": "node tools/createIssues.js"
}
@@ -58,7 +58,7 @@ Committing a simple nodejs script at `tools/createIssues.js` with only a `consol
Using the [axios](https://github.com/axios/axios) library I can list the existing issues in the blog-comment repo:
-``` javascript
+```javascript
const Axios = require('axios');
const BASIC_AUTH_HEADER = process.argv[2]; // [0] is "node", [1] is scriptname
@@ -70,7 +70,7 @@ const axios = Axios.create({
baseURL: 'https://api.github.com/',
headers: {
'User-Agent': 'statox',
- 'Authorization': `basic ${BASIC_AUTH_HEADER}`
+ Authorization: `basic ${BASIC_AUTH_HEADER}`
}
});
@@ -78,20 +78,22 @@ const axios = Axios.create({
* Get all of the open issues in a github repo
*/
function getIssues(cb) {
- return axios.get(
- `repos/${REPO_NAME}/issues`
- ).then((response) => {
- return cb(null, response.data)
- }).catch((error) => {
- return cb(error);
- });
+ return axios
+ .get(`repos/${REPO_NAME}/issues`)
+ .then((response) => {
+ return cb(null, response.data);
+ })
+ .catch((error) => {
+ return cb(error);
+ });
}
```
The other items to list are the posts. Here I needed to create a function to recursively list the files in my `src/posts` directory. These files have a header section delimited by `---` strings which are used by eleventy (the static site generator I used for this site). I created a function to parse these header and return a javascript object, that was a quick way to get things done without digging the doc but I'm sure there is a more efficient way to get this data out of eleventy. _(For example I could write this data directly in JS in the posts files)_
With this short function I list all my posts, get their title and the ID of the issue I associated to it and exclude the posts I have not published yet.
-``` javascript
+
+```javascript
/*
* Iterate through all the files found in the post folder
* Read them to get their data section
@@ -100,50 +102,59 @@ With this short function I list all my posts, get their title and the ID of the
function getPosts(cb) {
const files = walkSync('src/posts/');
- async.map(files, (file, cb) => {
- return fs.readFile(file, {encoding: 'utf-8'}, (error, content) => {
+ async.map(
+ files,
+ (file, cb) => {
+ return fs.readFile(file, { encoding: 'utf-8' }, (error, content) => {
+ if (error) {
+ return cb(error);
+ }
+
+ // Only keep the part between the two '---' lines
+ const postHeader = content.split('---')[1].split('\n');
+ return cb(null, convertPostHeader(postHeader));
+ });
+ },
+ (error, results) => {
if (error) {
return cb(error);
}
- // Only keep the part between the two '---' lines
- const postHeader = content.split('---')[1].split('\n')
- return cb(null, convertPostHeader(postHeader));
- });
- },
- (error, results) => {
- if (error) {
- return cb(error);
+ // Only keep the published posts
+ return cb(
+ null,
+ results.filter((p) => p.eleventyExcludeFromCollections !== true && p.title)
+ );
}
-
- // Only keep the published posts
- return cb(null, results.filter(p => p.eleventyExcludeFromCollections !== true && p.title));
- });
+ );
}
```
A bit more logic to detect the issues which need to be created and an additional call to the Github API and here is our working script:
-``` javascript
+```javascript
/*
* Post a new issue on github
*/
function createIssue(issue, cb) {
if (DRY_RUN) {
- console.log('DRY RUN: creating issue', {issue});
+ console.log('DRY RUN: creating issue', { issue });
return cb();
}
- return axios.post(
- `repos/${REPO_NAME}/issues`,
- JSON.stringify({
- title: issue.title,
+ return axios
+ .post(
+ `repos/${REPO_NAME}/issues`,
+ JSON.stringify({
+ title: issue.title
+ })
+ )
+ .then((response) => {
+ return cb(null, response.data);
})
- ).then((response) => {
- return cb(null, response.data)
- }).catch((error) => {
- return cb(error);
- });
+ .catch((error) => {
+ return cb(error);
+ });
}
```
@@ -153,7 +164,7 @@ I added a `DRY_RUN` variable which comes from how I call the script for testing
Using the `commentIssueId` of each post and the following script allows to inject the comments in the comment section:
-``` javascript
+```javascript
// Script to inject comments based on github issues
// Shamelessly taken from https://25.wf/posts/2020-06-21-comments.html
function domReady(fn) {
@@ -168,7 +179,7 @@ async function getComments(url = '') {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
- headers: { Accept: 'application/vnd.github.v3.html+json' },
+ headers: { Accept: 'application/vnd.github.v3.html+json' }
});
return response.json();
}
@@ -185,11 +196,11 @@ domReady(() => {
commentSection.insertAdjacentHTML(
'beforeend',
'
',
+ `• ${comment.user.login}` +
+ ' on' +
+ ` ${new Date(comment.created_at).toUTCString()}` +
+ comment.body_html +
+ ''
);
});
};
@@ -199,15 +210,15 @@ domReady(() => {
### So much time saved!
-And that's how I came up with a system which makes me save about one minute every time I publish a new post (which doesn't happen more than a few time a month at best)! It took me about 4 hours to get the whole thing working so according to this famous XKCD... that might have been a bit of a waste of time, but it was fun to do! :sweat_smile:
+And that's how I came up with a system which makes me save about one minute every time I publish a new post (which doesn't happen more than a few time a month at best)! It took me about 4 hours to get the whole thing working so according to this famous XKCD... that might have been a bit of a waste of time, but it was fun to do! :sweat_smile:

I still have a few more things I want to implement:
- - Improving how I handle the data coming from the posts to avoid parsing it myself
- - Adding a check to make sure my posts all have unique and sequential issues ID
- - Adding a mechanism to update the title of the issues if the title of the post change
- - Adding a content to the OP of the issue to have a link to the article
+- Improving how I handle the data coming from the posts to avoid parsing it myself
+- Adding a check to make sure my posts all have unique and sequential issues ID
+- Adding a mechanism to update the title of the issues if the title of the post change
+- Adding a content to the OP of the issue to have a link to the article
But given the previous XKCD graph I'll see when I have time for that and if I really have a need for it too.
diff --git a/src/posts/2020/07/vim_flash_yanked_text/index.md b/src/posts/2020/07/vim_flash_yanked_text/index.md
index db1961910..9989c9242 100644
--- a/src/posts/2020/07/vim_flash_yanked_text/index.md
+++ b/src/posts/2020/07/vim_flash_yanked_text/index.md
@@ -8,7 +8,7 @@ title: Highlighting yanked text with pure vimscript
A few days ago I saw [a blog post](https://blog.kdheepak.com/three-built-in-neovim-features.html#highlight-yanked-text) showing a built-in way to highlight yanked text on neovim. The author uses neovim's lua integration combined with the [`:h TextYankPost`](https://neovim.io/doc/user/autocmd.html#TextYankPost) autocommand event:
-``` vim
+```vim
augroup highlightYankedText
autocmd!
autocmd TextYankPost * silent! lua require'vim.highlight'.on_yank()
@@ -29,23 +29,23 @@ In this article I will to relate the main steps I followed to get this feature w
First a bit of Vim terminology about highlighting:
- - A `pattern` is basically a regular expression which can be used to search for some text.
+- A `pattern` is basically a regular expression which can be used to search for some text.
- Patterns can be as simple as plain text (e.g. `/TODO` ) or complex regexes with a lot of items as described in [`:h pattern`](http://vimhelp.appspot.com/pattern.txt.html#pattern).
+ Patterns can be as simple as plain text (e.g. `/TODO` ) or complex regexes with a lot of items as described in [`:h pattern`](http://vimhelp.appspot.com/pattern.txt.html#pattern).
- - A `highlighting group` is a named group of highlighting instructions.
+- A `highlighting group` is a named group of highlighting instructions.
- The [`:highlight`](http://vimhelp.appspot.com/syntax.txt.html#%3Ahighlight) command allows to list the existing groups when given no arguments. It also allows to create new groups or get details about the existing ones. By default both Vim and Neovim have an `IncSearch` highlighting group which we will reuse to highlight our text. You can see what it looks like on your system with the command `:highlight IncSearch`
+ The [`:highlight`](http://vimhelp.appspot.com/syntax.txt.html#%3Ahighlight) command allows to list the existing groups when given no arguments. It also allows to create new groups or get details about the existing ones. By default both Vim and Neovim have an `IncSearch` highlighting group which we will reuse to highlight our text. You can see what it looks like on your system with the command `:highlight IncSearch`
- - Finally a `match` is a way to tell Vim to highlight a specific pattern using a specific highlighting group.
+- Finally a `match` is a way to tell Vim to highlight a specific pattern using a specific highlighting group.
- A match can be created with [`matchadd()`](http://vimhelp.appspot.com/eval.txt.html#matchadd%28%29). The first argument is the name of an highlighting group as shown in the result of `:highlight` and the second argument is a pattern:
+ A match can be created with [`matchadd()`](http://vimhelp.appspot.com/eval.txt.html#matchadd%28%29). The first argument is the name of an highlighting group as shown in the result of `:highlight` and the second argument is a pattern:
- ```vim
- let id = matchadd('IncSearch', 'TODO')
- ```
+ ```vim
+ let id = matchadd('IncSearch', 'TODO')
+ ```
- To delete a match simply use the ID returned by the previous command. Note that this command only works in the window where the match was created, this will be important later on.
+ To delete a match simply use the ID returned by the previous command. Note that this command only works in the window where the match was created, this will be important later on.
```vim
call matchdelete(id)
@@ -63,10 +63,10 @@ let g:idTemporaryHighlight = matchadd('IncSearch', "\\%'\\[.*\\%']")
The main items of the pattern are the following:
- - `'[` is the mark I mentioned before but `[` being a special character (used in [`:h /[]`](http://vimhelp.appspot.com/pattern.txt.html#%2f%5b%5d)) it needs to be escaped hence `'\\[`. Note that each `\` needs to be escaped to be used in the command.
- - Given this previous point, `\\%'\\[` is the way to use [`:h /\%'m`](http://vimhelp.appspot.com/pattern.txt.html#%2f%5c%25%27m) with the `'[` mark, matching the beginning of the previously yanked text.
- - `.*` allows to match any characters any number of time.
- - `\\%']` is the equivalent of the first item with the `']` mark. Note that here `]` doesn't need to be escaped since there is no risk of confusion with [`:h /[]`](http://vimhelp.appspot.com/pattern.txt.html#%2f%5b%5d).
+- `'[` is the mark I mentioned before but `[` being a special character (used in [`:h /[]`](http://vimhelp.appspot.com/pattern.txt.html#%2f%5b%5d)) it needs to be escaped hence `'\\[`. Note that each `\` needs to be escaped to be used in the command.
+- Given this previous point, `\\%'\\[` is the way to use [`:h /\%'m`](http://vimhelp.appspot.com/pattern.txt.html#%2f%5c%25%27m) with the `'[` mark, matching the beginning of the previously yanked text.
+- `.*` allows to match any characters any number of time.
+- `\\%']` is the equivalent of the first item with the `']` mark. Note that here `]` doesn't need to be escaped since there is no risk of confusion with [`:h /[]`](http://vimhelp.appspot.com/pattern.txt.html#%2f%5b%5d).
This is a great first attempt which kind of works on some simple cases but fails when yanking text on several lines. This is because the [`.`](http://vimhelp.appspot.com/pattern.txt.html#%2f.) atom doesn't match end of lines characters, so we need to use [`\_.`](http://vimhelp.appspot.com/pattern.txt.html#%2f%5c_.) instead:
@@ -76,11 +76,11 @@ let g:idTemporaryHighlight = matchadd('IncSearch', "\\%'\\[\\_.*\\%']")
That is better but still not completely working, for example the first and last characters of the yanked text are not highlighted. That's the moment where we turn to the doc and read a bit more what [`:h /\%'m`](http://vimhelp.appspot.com/pattern.txt.html#%2f%5c%25%27m) has to say, particularly this:
- Example, to highlight the text from mark 's to 'e:
- /.\%>'s.*\%<'e..
- Note that two dots are required to include mark 'e in the match. That
- is because "\%<'e" matches at the character before the 'e mark, and
- since it's a |/zero-width| match it doesn't include that character.
+ Example, to highlight the text from mark 's to 'e:
+ /.\%>'s.*\%<'e..
+ Note that two dots are required to include mark 'e in the match. That
+ is because "\%<'e" matches at the character before the 'e mark, and
+ since it's a |/zero-width| match it doesn't include that character.
Easy peasy, let's reuse the same thing but with our marks `'[` and `']`:
@@ -88,7 +88,7 @@ Easy peasy, let's reuse the same thing but with our marks `'[` and `']`:
let g:idTemporaryHighlight = matchadd('IncSearch', ".\\%>'\\[\\_.*\\%<']..")
```
-*Important note*: Some of this escaping could be greatly simplified using a different magic mode but it's not my point here. For more information on magic in Vim see [`:h /magic`](http://vimhelp.appspot.com/pattern.txt.html#%2fmagic)
+_Important note_: Some of this escaping could be greatly simplified using a different magic mode but it's not my point here. For more information on magic in Vim see [`:h /magic`](http://vimhelp.appspot.com/pattern.txt.html#%2fmagic)
So after a few tests yanking some random text, using `matchadd` to highlight it and `matchdelete` to remove the highlighting I am satisfied with the result, it is then time to automatically highlight our text.
@@ -96,7 +96,7 @@ So after a few tests yanking some random text, using `matchadd` to highlight it
Vim provides since it [patch 8.0.1394](https://github.com/vim/vim/commit/7e1652c63c96585b9e2235c195a3c322b1f11595) the [`:h TextYankPost`](http://vimhelp.appspot.com/autocmd.txt.html#TextYankPost) autocommand event which triggers just after a yank or deleting command. So our first step is to create a function triggered by this event:
-``` vim
+```vim
augroup highlightYankedText
autocmd!
autocmd TextYankPost * call FlashYankedText()
@@ -111,8 +111,7 @@ As you can see I put my autocommand in an [`augroup`](http://vimhelp.appspot.com
That is great! Each time we yank some text it gets highlighted... but then it remains highlighted indefinitely. So let's simply use a timer to delete the match we just created. Note that the function puts the id of the newly created match in a global variable which is kind of ugly but pretty pratical to access it in the `DeleteTemporaryMatch()` function.
-
-``` vim
+```vim
function! FlashYankedText()
let g:idTemporaryHighlight = matchadd('IncSearch', ".\\%>'\\[\\_.*\\%<']..")
call timer_start(500, 'DeleteTemporaryMatch')
@@ -127,8 +126,8 @@ endfunction
The previous code kind of works but some edge cases are problematic:
-- When I yank two different texts too quickly sometimes the `DeleteTemporaryMatch()` function doesn't have the time to delete the previous match.
-- More importantly, when I switch to another window just after yanking some text, `deletematches()` fails because the matches id are local to a window.
+- When I yank two different texts too quickly sometimes the `DeleteTemporaryMatch()` function doesn't have the time to delete the previous match.
+- More importantly, when I switch to another window just after yanking some text, `deletematches()` fails because the matches id are local to a window.
So let's put the ids in a list, with the window id where they were created:
diff --git a/src/posts/2020/10/asteroids/asteroids.md b/src/posts/2020/10/asteroids/asteroids.md
index 1252fb40f..076426ce0 100644
--- a/src/posts/2020/10/asteroids/asteroids.md
+++ b/src/posts/2020/10/asteroids/asteroids.md
@@ -6,7 +6,7 @@ commentIssueId: 15
title: Asteroids... with real pew pews
---
-Asteroids! The game is as old as the world (well almost, it was [released in 1979](https://en.wikipedia.org/wiki/Asteroids_(video_game))) and is an iconic figure of the golden era of the video game.
+Asteroids! The game is as old as the world (well almost, it was [released in 1979]()) and is an iconic figure of the golden era of the video game.

@@ -18,7 +18,7 @@ So after a few hours of code and some really crappy recording on my phone [here
No technological innovation or mind blowing creativity here but the result still amuses me more than I would be willing to admit. I feel like I am re-discovering the early 2000's flash games and that's fun!
-To make it a complete game I still implemented some bonuses, like the autopews and the triple pew which allow respectively to continuously shoot at the asteroids and to shoot in 3 directions, as well as some maluses like slowing down the spaceship rotation speed or locking its engine on to force the player to get good at slaloming between the rocks at full speed. I also used my own noise function (actually a wrapper around p5js's `noise()` function) to generate random rocks which *kinda* look like asteroids.
+To make it a complete game I still implemented some bonuses, like the autopews and the triple pew which allow respectively to continuously shoot at the asteroids and to shoot in 3 directions, as well as some maluses like slowing down the spaceship rotation speed or locking its engine on to force the player to get good at slaloming between the rocks at full speed. I also used my own noise function (actually a wrapper around p5js's `noise()` function) to generate random rocks which _kinda_ look like asteroids.
But let's be real despite all these amazing features the main interest of the game is hearing my dumb "pew pew" and "boum" for five minutes before it gets annoying.
diff --git a/src/posts/2020/10/breath/index.md b/src/posts/2020/10/breath/index.md
index 0d06a8197..5ca7b8230 100644
--- a/src/posts/2020/10/breath/index.md
+++ b/src/posts/2020/10/breath/index.md
@@ -26,8 +26,8 @@ The first step was to create a [codepen](https://codepen.io/statox/pen/abNVYZZ)
That resulted in some pretty rough animations and a not very well organized code, but at least it allowed me to validate what are the two main components I would need to implement in my project:
-- Some kind of state processing to handle the transitions between the "breath in" and "breath out" phases (as well as two additional "pause" phases, which I find more comfortable to add);
-- A "pluggable architecture" where I can write independent functions for different animations and only have to plug them in the existing canvas.
+- Some kind of state processing to handle the transitions between the "breath in" and "breath out" phases (as well as two additional "pause" phases, which I find more comfortable to add);
+- A "pluggable architecture" where I can write independent functions for different animations and only have to plug them in the existing canvas.
-- The saturation is how rich the color is: A 100% saturation is very colorful while a 0% saturation is grey. With a 0% saturation no matter which hue you use you will always get the same grey
-
-
- 0%
- 25%
- 50%
- 75%
- 100%
-
-
- 0%
- 25%
- 50%
- 75%
- 100%
-
-
-- The brightness is how... bright is your color? Simply put: 0% brightness is complete black no matter the hue, 100% is white if saturation is 0% or just a very bright color.
-
- 0%
- 25%
- 50%
- 75%
- 100%
-
-
- 0%
- 25%
- 50%
- 75%
- 100%
-
+- **HSB** stands for **H**ue, **S**aturation and **B**rightness.
+- The hue value represent the raw color. It is expressed as an angle as shown on the color wheel here. This angle is between `0`-`360` degrees, but in a p5 sketch we map these values to the range `0`-`100`, and in a shader we will map it in the range `0.0`-`1.0`. But no matter which range we use the relative difference between the color is always the same.
+ 
+
+- The saturation is how rich the color is: A 100% saturation is very colorful while a 0% saturation is grey. With a 0% saturation no matter which hue you use you will always get the same grey
+
+
+ 0%
+ 25%
+ 50%
+ 75%
+ 100%
+
+
+ 0%
+ 25%
+ 50%
+ 75%
+ 100%
+
+
+- The brightness is how... bright is your color? Simply put: 0% brightness is complete black no matter the hue, 100% is white if saturation is 0% or just a very bright color.
+
+ 0%
+ 25%
+ 50%
+ 75%
+ 100%
+
+
+ 0%
+ 25%
+ 50%
+ 75%
+ 100%
+
Note that you'll also find online some references to the color systems **HSV** and **HSL**. If I believe the wikipedia page **HSV** is the exact same thing as **HSB** excepted **B**rightness is named **V**alue. And **HSL** is **H**ue, **S**aturation, **L**ightness which is kind of the inverse of Brightness (if you want details, check wiki they explain it better than I'll do).
-
### Our first shader
Now that we know what our project should look like and we understand our color system let's get started with shaders! The first step is to use a very basic shader in a p5js project. Fortunately the doc gives [a good example](https://p5js.org/examples/3d-basic-shader.html) of a very simple usage:
-
```javascript
// this variable will hold our shader object
let theShader;
-function preload(){
+function preload() {
// load the shader
theShader = loadShader('assets/basic.vert', 'assets/basic.frag');
}
@@ -127,8 +125,8 @@ function draw() {
This will use a shader named `basic` to draw a rectangle on screen. The interesting part is then to implement this shader. As we can see in the `loadShader()` call we need 2 files to define a shader:
-- `shader.vert`
-- `shader.frag`
+- `shader.vert`
+- `shader.frag`
These files are written with [GLSL](https://en.wikipedia.org/wiki/OpenGL_Shading_Language) which is a widely used language to program shaders, this is the language we will use the shader files in the articles.
@@ -216,7 +214,7 @@ vec3 hsb2rgb(vec3 c)
void main() {
// Normalize the position (to be in range 0.0 - 1.0)
// The .xy notation applies the same operation on both x and y components
- vec2 st = gl_FragCoord.xy/u_resolution.xy;
+ vec2 st = gl_FragCoord.xy/u_resolution.xy;
// Use the x position of the pixel to define its hue
// (with saturation and brightness to 1)
@@ -273,7 +271,7 @@ vec3 hsb2rgb(vec3 c)
void main() {
// Normalize the position between 0 and 1
- vec2 st = gl_FragCoord.xy/u_resolution.xy;
+ vec2 st = gl_FragCoord.xy/u_resolution.xy;
// Set the pixel color using the current hue
// and the position to make a gradient
@@ -286,8 +284,8 @@ void main() {
The principle is very similar to the rainbow shader, two things change:
-- First we pass new uniform `u_hue` which determines the hue selected by the user. This hue is passed as a float ranging from `0.0` to `1.0` by the p5 sketch.
-- Then we use this hue as well as the normalized position to get the color of the pixel.
+- First we pass new uniform `u_hue` which determines the hue selected by the user. This hue is passed as a float ranging from `0.0` to `1.0` by the p5 sketch.
+- Then we use this hue as well as the normalized position to get the color of the pixel.
In the `draw()` function we will use the following line to set the hue depending on the x component of the mouse position:
@@ -310,8 +308,8 @@ Now comes the part where we put everything together to get a working color picke
The user will have two ways to interact with the picker:
-- When they click on the rainbow and move the mouse on it we will update the hue used in the picker rectangle.
-- When they click the picker and move the mouse on it we will update the saturation and brightness.
+- When they click on the rainbow and move the mouse on it we will update the hue used in the picker rectangle.
+- When they click the picker and move the mouse on it we will update the saturation and brightness.
Each change in hue, saturation or brightness will be reflected in the sample rectangle showing the currently selected color.
@@ -438,15 +436,15 @@ An online demo is available [here](https://statox.github.io/color-picker/), it d
### A new world of opportunities
-This project was really fun to do and I hope that if you never played with shaders before it gave you some inspiration to do the same! I am really excited to use this new skill I learned because I've done [a few](https://www.statox.fr/posts/2020/11/ants/) [simulations](https://www.statox.fr/posts/2020/09/boids/) in the browser with p5 before but they were all limited by their performances. Offloading some of the work to the GPU should allow me to create simulations with much larger definitions. I'm thinking about trying to make a [Critters cellular automaton](https://en.wikipedia.org/wiki/Critters_(cellular_automaton)), exploring [fractal](https://www.shadertoy.com/view/lsX3W4) or maybe maps generation as seen in some of [Sebastian Lague's videos](https://www.youtube.com/channel/UCmtyQOKKmrMVaKuRXz02jbQ).
+This project was really fun to do and I hope that if you never played with shaders before it gave you some inspiration to do the same! I am really excited to use this new skill I learned because I've done [a few](https://www.statox.fr/posts/2020/11/ants/) [simulations](https://www.statox.fr/posts/2020/09/boids/) in the browser with p5 before but they were all limited by their performances. Offloading some of the work to the GPU should allow me to create simulations with much larger definitions. I'm thinking about trying to make a [Critters cellular automaton](), exploring [fractal](https://www.shadertoy.com/view/lsX3W4) or maybe maps generation as seen in some of [Sebastian Lague's videos](https://www.youtube.com/channel/UCmtyQOKKmrMVaKuRXz02jbQ).
If you also want to get started with shaders here is a list of some interesting resources:
-- [itp-xstory.github.io](https://itp-xstory.github.io/p5js-shaders) - An amazing introduction to using shaders with p5js
-- [aferriss/p5jsShaderExamples](https://github.com/aferriss/p5jsShaderExamples) - Some useful examples of GLSL shaders for p5js
-- [p5js.org](https://p5js.org/reference/#/p5/shader) - The p5js doc about shaders
-- [lea.codes](https://lea.codes/webgl/) - The personal website of a dev who does cool things with shaders and threejs
-- [The book of shaders](https://thebookofshaders.com/) - The Bible of shader programming
+- [itp-xstory.github.io](https://itp-xstory.github.io/p5js-shaders) - An amazing introduction to using shaders with p5js
+- [aferriss/p5jsShaderExamples](https://github.com/aferriss/p5jsShaderExamples) - Some useful examples of GLSL shaders for p5js
+- [p5js.org](https://p5js.org/reference/#/p5/shader) - The p5js doc about shaders
+- [lea.codes](https://lea.codes/webgl/) - The personal website of a dev who does cool things with shaders and threejs
+- [The book of shaders](https://thebookofshaders.com/) - The Bible of shader programming
If you know of other good resources or want to discuss a project idea, leave a comment on this article!
diff --git a/src/posts/2021/04/firefox_autohide_bookmarks.md b/src/posts/2021/04/firefox_autohide_bookmarks.md
index 8666dfff0..5d472a4c9 100644
--- a/src/posts/2021/04/firefox_autohide_bookmarks.md
+++ b/src/posts/2021/04/firefox_autohide_bookmarks.md
@@ -12,10 +12,10 @@ A very quick tip that I don't want to forget about: One can automatically hide t
The `userChrome.css` file holds style rules for modifying Firefox's user interface. [This website](https://www.userchrome.org) is a good learning resource.
-On linux the file is either in
+On linux the file is either in
- - `$HOME/.mozilla/firefox/[PROFILE_ID].default/chrome/userChrome.css`
- - or `$HOME/snap/firefox/common/.mozilla/firefox/[PROFILE_ID].default/chrome/userChrome.css` if you use the snap version
+- `$HOME/.mozilla/firefox/[PROFILE_ID].default/chrome/userChrome.css`
+- or `$HOME/snap/firefox/common/.mozilla/firefox/[PROFILE_ID].default/chrome/userChrome.css` if you use the snap version
To locate the profile currently used by Firefox one can visit `about:support` and check the line `Profile Directory`.
@@ -29,42 +29,49 @@ The code is available on [MrOtherGuy's Github](https://github.com/MrOtherGuy/fir
/* Source file https://github.com/MrOtherGuy/firefox-csshacks/tree/master/chrome/autohide_bookmarks_toolbar.css made available under Mozilla Public License v. 2.0
See the above repository for updates as well as full license text. */
-#PersonalToolbar{
- --uc-bm-height: 20px; /* Might need to adjust if the toolbar has other buttons */
- --uc-bm-padding: 4px; /* Vertical padding to be applied to bookmarks */
- --uc-autohide-toolbar-delay: 600ms; /* The toolbar is hidden after 0.6s */
+#PersonalToolbar {
+ --uc-bm-height: 20px; /* Might need to adjust if the toolbar has other buttons */
+ --uc-bm-padding: 4px; /* Vertical padding to be applied to bookmarks */
+ --uc-autohide-toolbar-delay: 600ms; /* The toolbar is hidden after 0.6s */
- /* 0deg = "show" ; 90deg = "hide" ; Set the following to control when bookmarks are shown */
- --uc-autohide-toolbar-focus-rotation: 0deg; /* urlbar is focused */
- --uc-autohide-toolbar-hover-rotation: 0deg; /* cursor is over the toolbar area */
+ /* 0deg = "show" ; 90deg = "hide" ; Set the following to control when bookmarks are shown */
+ --uc-autohide-toolbar-focus-rotation: 0deg; /* urlbar is focused */
+ --uc-autohide-toolbar-hover-rotation: 0deg; /* cursor is over the toolbar area */
}
-:root[uidensity="compact"] #PersonalToolbar{ --uc-bm-padding: 1px }
-:root[uidensity="touch"] #PersonalToolbar{ --uc-bm-padding: 7px }
+:root[uidensity='compact'] #PersonalToolbar {
+ --uc-bm-padding: 1px;
+}
+:root[uidensity='touch'] #PersonalToolbar {
+ --uc-bm-padding: 7px;
+}
-#PersonalToolbar:not([customizing]){
- position: relative;
- margin-bottom: calc(0px - var(--uc-bm-height) - 2 * var(--uc-bm-padding));
- transform: rotateX(90deg);
- transform-origin: top;
- transition: transform 135ms linear var(--uc-autohide-toolbar-delay) !important;
- z-index: 1;
+#PersonalToolbar:not([customizing]) {
+ position: relative;
+ margin-bottom: calc(0px - var(--uc-bm-height) - 2 * var(--uc-bm-padding));
+ transform: rotateX(90deg);
+ transform-origin: top;
+ transition: transform 135ms linear var(--uc-autohide-toolbar-delay) !important;
+ z-index: 1;
}
-#PlacesToolbarItems > .bookmark-item{ padding-block: var(--uc-bm-padding) !important; }
+#PlacesToolbarItems > .bookmark-item {
+ padding-block: var(--uc-bm-padding) !important;
+}
-#nav-bar:focus-within + #PersonalToolbar{
- transition-delay: 100ms !important;
- transform: rotateX(var(--uc-autohide-toolbar-focus-rotation,0));
+#nav-bar:focus-within + #PersonalToolbar {
+ transition-delay: 100ms !important;
+ transform: rotateX(var(--uc-autohide-toolbar-focus-rotation, 0));
}
-#navigator-toolbox:hover > #PersonalToolbar{
- transition-delay: 100ms !important;
- transform: rotateX(var(--uc-autohide-toolbar-hover-rotation,0));
+#navigator-toolbox:hover > #PersonalToolbar {
+ transition-delay: 100ms !important;
+ transform: rotateX(var(--uc-autohide-toolbar-hover-rotation, 0));
}
-#navigator-toolbox:hover > #nav-bar:focus-within + #PersonalToolbar {
- transform: rotateX(0);
+#navigator-toolbox:hover > #nav-bar:focus-within + #PersonalToolbar {
+ transform: rotateX(0);
}
```
+
diff --git a/src/posts/2021/05/javascript_golf_tips/index.md b/src/posts/2021/05/javascript_golf_tips/index.md
index 97593cc91..7cf4e3148 100644
--- a/src/posts/2021/05/javascript_golf_tips/index.md
+++ b/src/posts/2021/05/javascript_golf_tips/index.md
@@ -16,6 +16,7 @@ I love to play on [codingame](https://www.codingame.com) it's a great way to kee
There are several types of clashes (fastest to get the right solution, reverse engineering and shortest code) and recently the shortest code became one of my favorite. Since I start to have a decent ranking I compiled some tricks I use in javascript to shorten my code. Some save several bytes and other only save a few but learning how to combine them and when to use them can lead a long way.

+
My ranking on 13/06/23: 78/571.284 Top 0.01%😎
@@ -24,8 +25,8 @@ There are several types of clashes (fastest to get the right solution, reverse e
A list of the various codingame problems with their stats: [chadok.info](https://chadok.info/codingame/puzzles_list.html)
-
### Type conversions
+
#### Decimal string to Number
When an input is expected to be a number examples usually use the following code:
@@ -37,24 +38,24 @@ n = parseInt(readline());
This is 10 characters just to parse a number from a string. Using the unary operator `+` on a string will cast it to a number. Example:
```javascript
-let s='12';
-let n=+s;
+let s = '12';
+let n = +s;
typeof n; // 'number'
-let t=+s[0]+s[1]; // t=3
+let t = +s[0] + s[1]; // t=3
```
Note that if you need to add a variable which is a number to a string representing a number you will need to use the string first or add a whitespace before the `+` operator:
```javascript
-let s='1';
-let n=1;
+let s = '1';
+let n = 1;
-n+s; // string: '11'
-n+ +s; // number: 2
+n + s; // string: '11'
+n + +s; // number: 2
-+s+n // number: 2
++s + n; // number: 2
```
#### Binary string to Number
@@ -66,14 +67,15 @@ Number('0b101'); // 5
```
#### Number to binary string
+
See [this SO answer](https://stackoverflow.com/a/16155417)
+
```javascript
-let a=6;
+let a = 6;
a.toString(2); // '110'
// For negative numbers
-let a=-6
-(a >>> 0).toString(2)
+let a = -6(a >>> 0).toString(2);
```
### ASCII
@@ -86,23 +88,22 @@ let a=-6
### Position in the alphabet
```javascript
+'a'.charCodeAt(0) - 97; // 0
+'b'.charCodeAt(0) - 97; // 1
+'c'.charCodeAt(0) - 97; // 2
-'a'.charCodeAt(0)-97 // 0
-'b'.charCodeAt(0)-97 // 1
-'c'.charCodeAt(0)-97 // 2
-
-'A'.charCodeAt(0)-65 // 0
-'B'.charCodeAt(0)-65 // 1
-'C'.charCodeAt(0)-65 // 2
+'A'.charCodeAt(0) - 65; // 0
+'B'.charCodeAt(0) - 65; // 1
+'C'.charCodeAt(0) - 65; // 2
```
If not considering the case
```javascript
-parseInt(c,36)-10;
+parseInt(c, 36) - 10;
// Example
-[...'abcdefghijklmnopqrstuvwxyz'].map(c => parseInt(c, 36)-10); // [0, 1, 2, 3..., 25];
+[...'abcdefghijklmnopqrstuvwxyz'].map((c) => parseInt(c, 36) - 10); // [0, 1, 2, 3..., 25];
```
### Loops
@@ -133,7 +134,11 @@ for(b=realine(a=readline();a+c) // Better
-for(c of l)t+=+c // Top
+l.map(Number); // Good
+l.map((c) => +c); // Better
+for (c of l) t += +c; // Top
```
### Variables declaration and initialization
@@ -156,14 +161,14 @@ You should always have in mind the implications of not implicit scopes but that
```javascript
// 58 bytes
-let n=10;
-for(let i=0; i>1
-i/4|0 === i>>2
+(i / 2) | (0 === i >> 1);
+(i / 4) | (0 === i >> 2);
```
#### Get rid of leading zeros
```javascript
-0.5 === .5 // true
+0.5 === 0.5; // true
```
### Conditions
+
#### The ternary operator
[The ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) is precious to avoid lengthy conditional expressions.
@@ -225,11 +232,11 @@ i/4|0 === i>>2
Always be mindful of what you use in your conditional expressions, sometimes putting them in another way can save a byte or two while preserving the same feature:
```javascript
-r=a<10?a+'0':a
-r=a>9?a:a+'0'
+r = a < 10 ? a + '0' : a;
+r = a > 9 ? a : a + '0';
-r=a==b?'same':a>b?'higher':'lower'
-r=a>b?'higher':a b ? 'higher' : 'lower';
+r = a > b ? 'higher' : a < b ? 'lower' : 'same';
```
#### Using `&&` and `||`
@@ -246,18 +253,20 @@ Consider a problem where you need to find the `n`th digit in a string of all pal
You will need to generate the string `123456789112233445566778899101...`. One way to do it is the following:
```javascript
-for(n=+readline(s=""),i=0;!s[n];i++)if([...i+""].reverse().join``==i){s+=i}
-print(s[n])
+for (n = +readline((s = '')), i = 0; !s[n]; i++)
+ if ([...(i + '')].reverse().join`` == i) {
+ s += i;
+ }
+print(s[n]);
```
While the `n`th digit of the string doesn't exists continue to search for number which are palindromes.
```javascript
-for(n=+readline(s=""),i=0;!s[n];i++)([...i+""].reverse().join``==i)&&(s+=i)
-print(s[n])
+for (n = +readline((s = '')), i = 0; !s[n]; i++) [...(i + '')].reverse().join`` == i && (s += i);
+print(s[n]);
```
-
### Codingame particularities
These tips are only useful on the codingame website.
@@ -270,13 +279,13 @@ If you need to use `readline()` more than one it will be cheaper to store it in
```javascript
// 27 bytes
-n=readline()
-m=readline()
+n = readline();
+m = readline();
// 24 bytes
-r=readline
-n=r()
-m=r()
+r = readline;
+n = r();
+m = r();
```
This is only 3 characters saved but the more calls to `readline()` you need to write the more characters you save.
@@ -286,20 +295,21 @@ This is only 3 characters saved but the more calls to `readline()` you need to w
You can use javascript scope smartly to reduce the number of bytes needed to get the inputs. To do so keep in mind that if you pass a variable assignation as the argument of a function the variable is still available in your current scope.
For example let's say you need to read two strings `n` and `m` and to init a counter `i` to zero:
+
```javascript
// 28 bytes
-r=readline
-n=r()
-m=r()
-i=0
+r = readline;
+n = r();
+m = r();
+i = 0;
```
This can be shortened like this:
```javascript
// 26 bytes
-r=readline
-m=r(n=r(i=0))
+r = readline;
+m = r((n = r((i = 0))));
```
⚠ The order of calls made to `r()` is important here: The first call made to the function should be the most nested.
@@ -309,12 +319,8 @@ m=r(n=r(i=0))
I'm not completely sure how this trick works because I can't reproduce it in a browser or in node, but in codingame if you need to pass a string as an argument you can avoid the whole `('string')` syntax with a pair of back ticks. This can be useful to split a string or join an array:
```javascript
-'ab cd ef'.split(' ')
-'ab cd ef'.split` `
-
-[1, 2, 3].join('\r')
-[1, 2, 3].join`\r`
-
+'ab cd ef'.split(' ');
+'ab cd ef'.split` `[(1, 2, 3)].join('\r')[(1, 2, 3)].join`\r`;
```
#### Replace `console.log` by `print`
@@ -322,8 +328,8 @@ I'm not completely sure how this trick works because I can't reproduce it in a b
To pass your result to codingame validators you need to write it to the standard output. In regular javascript this is done with `console.log` however codingame's environment supports the deprecated `print` which works exactly the same:
```javascript
-console.log('valid')
-print('valid')
+console.log('valid');
+print('valid');
```
#### Stop your program with an invalid command
diff --git a/src/posts/2021/10/race_generator.md b/src/posts/2021/10/race_generator.md
index 4235181e6..8ca0deaf9 100644
--- a/src/posts/2021/10/race_generator.md
+++ b/src/posts/2021/10/race_generator.md
@@ -8,18 +8,18 @@ commentIssueId: 29
For several weeks now I have been working on and off on an ambitious project in which I want to procedurally generate a racetrack to create autonomous vehicles which will learn to drive on it thanks to a genetic algorithm. I did a lot of different experiments and even got some ~~cool~~ passable results but I am hitting a point where there is too much refactoring to be done to complete the project with the current code base. As I don't have the motivation to put more work to do things properly and as I also have other projects in mind that I want to start working on I'm writing this post to keep a trace of what I have done and what I would like to do differently. This writing will be messy and probably not very interesting for anyone else than myself but I hope that it will be helpful in a few months when I decide to build something on top of this experiment.
-
### Generating a racetrack
My goal was to generate a racetrack which would be a loop with several turns with angles sufficiently difficult to be interesting. To do that I took a lot of inspiration from these two articles:
- - [How to generate procedural racetracks](http://blog.meltinglogic.com/2013/12/how-to-generate-procedural-racetracks/)
- - [Procedural racetrack generation](https://bitesofcode.wordpress.com/2020/04/09/procedural-racetrack-generation/)
+- [How to generate procedural racetracks](http://blog.meltinglogic.com/2013/12/how-to-generate-procedural-racetracks/)
+- [Procedural racetrack generation](https://bitesofcode.wordpress.com/2020/04/09/procedural-racetrack-generation/)
In the first post Gustavo Maciel describes an idea to generate a racetrack in three simple steps:
- - Generate a bunch of random points in the plan
- - Calculate the hull of the polygon formed by these points. That is, simply put, the list which will wrap around all the points
- - Finally interpolate the points of this hull to get a nice racetracky shape on which a car could drive
+
+- Generate a bunch of random points in the plan
+- Calculate the hull of the polygon formed by these points. That is, simply put, the list which will wrap around all the points
+- Finally interpolate the points of this hull to get a nice racetracky shape on which a car could drive
The second post is a second implementation of Maciel's idea, and my project is yet another implementation of the same idea but with my _very own_ bugs and design flaws which makes it very special to my eyes 🤩.
@@ -54,10 +54,9 @@ Fortunately the page has a pseudo code implementation so I was able to port that
-
After this successful attempt I decided that the hulls generated were too boring: I want some deadly turns!
-The gift wrapping algorithm generates a convex hull which is a simple, boring envelope of the points. A concave hull however is a polygon with at least one angle between 180 and 360 degrees exclusive, which means that this polygon has a much more interesting shape with much more complex turns. It is however more complex to generate. So I explored the web a bit more and ended up on [Concave hull: A k-nearest neighbours approach for the computation of the region occupied by a set of points](https://repositorium.sdum.uminho.pt/bitstream/1822/6429/1/ConcaveHull_ACM_MYS.pdf). This paper describes an algorithm to generate a concave hull using the same idea as the gift wrapping but at each step, instead of choosing the next point among the complete list of generated point, we restrict the search the nearest neighbors of the current point.
+The gift wrapping algorithm generates a convex hull which is a simple, boring envelope of the points. A concave hull however is a polygon with at least one angle between 180 and 360 degrees exclusive, which means that this polygon has a much more interesting shape with much more complex turns. It is however more complex to generate. So I explored the web a bit more and ended up on [Concave hull: A k-nearest neighbours approach for the computation of the region occupied by a set of points](https://repositorium.sdum.uminho.pt/bitstream/1822/6429/1/ConcaveHull_ACM_MYS.pdf). This paper describes an algorithm to generate a concave hull using the same idea as the gift wrapping but at each step, instead of choosing the next point among the complete list of generated point, we restrict the search the nearest neighbors of the current point.
This looks much more interesting:
@@ -70,20 +69,19 @@ This looks much more interesting:
However with concave hull come two big issues:
-- It is not uncommon that two segments of the polygon intersect: that creates an issue because if you create a crossroad in a racetrack things get messy (Well, there _are_ some [figure 8 racing](https://youtu.be/6ZZyP7VlZcM) competitions but for our purpose that creates too many issues to count laps and detect if cars followed the right path)
-- Even when they don't intersect sometimes the vertices are at an angle which is just too narrow to make a good race track.
+- It is not uncommon that two segments of the polygon intersect: that creates an issue because if you create a crossroad in a racetrack things get messy (Well, there _are_ some [figure 8 racing](https://youtu.be/6ZZyP7VlZcM) competitions but for our purpose that creates too many issues to count laps and detect if cars followed the right path)
+- Even when they don't intersect sometimes the vertices are at an angle which is just too narrow to make a good race track.
There are several ways to get rid of these issues:
-- Detecting the intersection of two segments is super easy when you have a [`collideLineLine()`](https://github.com/bmoren/p5.collide2D/blob/0988172c15aeef/p5.collide2d.js#L196-L235) function like the one I shamelessly stole from the [p5.collide2D](https://github.com/bmoren/p5.collide2D) library. Determining the angle formed by three points and comparing it to an arbitrary threshold is enough too (cf. `threePointsAngle` in the previous codepen). Using this information one could simply ignore the bad tracks and keep generating new tracks until one fits all the criterion.
-- For intersections a correction can be made by taking the point where two lines intersect, making this point a new point of the hull replacing the ones which are in the inner loop.
-- For angles it is also possible to use the same principle as what I used to push my initial points apart: Take all your points, when three of them form an angle too narrow move one of them, and keep going until things are stable.
+- Detecting the intersection of two segments is super easy when you have a [`collideLineLine()`](https://github.com/bmoren/p5.collide2D/blob/0988172c15aeef/p5.collide2d.js#L196-L235) function like the one I shamelessly stole from the [p5.collide2D](https://github.com/bmoren/p5.collide2D) library. Determining the angle formed by three points and comparing it to an arbitrary threshold is enough too (cf. `threePointsAngle` in the previous codepen). Using this information one could simply ignore the bad tracks and keep generating new tracks until one fits all the criterion.
+- For intersections a correction can be made by taking the point where two lines intersect, making this point a new point of the hull replacing the ones which are in the inner loop.
+- For angles it is also possible to use the same principle as what I used to push my initial points apart: Take all your points, when three of them form an angle too narrow move one of them, and keep going until things are stable.
**I think that the important thing here anyway is to have your hull as clean as possible before you move on to the next step otherwise it will inevitably bite you.**
I'm putting the previous sentence in bold because of course I was too impatient to get to the next step so, of course, after thinking about the possible solutions for half an hour I decided to ignore the problem until it's too late.
-
#### Interpolating the points
Earlier this year I did [an experiment with Bezier curves](https://statox.github.io/bezier-experiment/) when this project was just a vague idea in the back of my mind. The basic idea is to generate a bunch of points (hence the two previous parts) to get a polygon and use the formula created by Bezier to add more points to this polygon to make the curves smoother.
@@ -99,7 +97,6 @@ So I kept my two hull algorithms (the gift wrapping and the k-nearest neighbors)
The results are quite nice we can see something which could look like a racetrack, that's the right path! However our issues with interesctions and narrow angles are still here and once again I decided that fixing them was a problem for future me 🤷.
-
#### Adding some width
So now I have a racetrack with a few hundreds points but they still form a simple line. There are a lot of options to make this line an actual road, my goal is to have cars detecting their position on the road with a ray tracing algorithm that I'll describe more later. To run this ray tracing I need to have a bunch of segments which represent the borders of my road.
@@ -117,7 +114,6 @@ Here you can see in blue the initial hull, in <
It's also at this point that I finally decided to start fixing the intersection issue. And of course I did it in a not very bright way: When the angle between three point is less than an arbitrary threshold I simply remove the middle point. That give this weird correction algorithm that you see in action in the previous codepen. And that introduces a worst problem which is that by doing that I change the width of the track on some portions.
-
While I was trying to fix this issue I also wondered how I would paint the road because p5.js doesn't have a way to create concave shapes. I came up with a simple solution which is to change the way I draw the line of the hull: By making the stroke weight much bigger I get something which looks even more like a racetrack:
@@ -129,7 +125,6 @@ While I was trying to fix this issue I also wondered how I would paint the road
With this implementation I thought I could display the track and have not-very-precise-but-still-good-enough border representation for the cars to run but realized that this is not good enough. So I came up with a solution which I find quite interesting.
-
#### Detecting that a car is not on the road
At this point I started merging everything I had done before into [a real Github project](https://www.github.com/statox/procedural-race/) with typescript, a real linter and all the right tools to develop this project properly. I tagged my commits properly at each steps so that I could showcase the progress of my project, but now I'm just too lazy to do that so I won't show demos.
@@ -138,12 +133,13 @@ One of the interesting ideas I had in the project was to find a way to easily ch
I think this is a pertinent approach as once the track is stored in memory the check is in constant time however my implementation was not the smartest:
-- As I draw the track on the canvas, I need to wait the first iteration of `draw()` to run to check the color of the canvas, this is super inconvenient. I should have drawn the track on a different `P5.Graphic` than the canvas this way I can do all the computations in `setup()` making the `draw()` function much simpler.
-- I should have normalized my track to a simple white on black display, instead I used the colors I has already started to use to show my track which makes the color comparison unnecessarily tricky.
+- As I draw the track on the canvas, I need to wait the first iteration of `draw()` to run to check the color of the canvas, this is super inconvenient. I should have drawn the track on a different `P5.Graphic` than the canvas this way I can do all the computations in `setup()` making the `draw()` function much simpler.
+- I should have normalized my track to a simple white on black display, instead I used the colors I has already started to use to show my track which makes the color comparison unnecessarily tricky.
### Making smart cars
#### Ray tracing
+
As I am impatient and stubborn I started creating my vehicles before my racetrack was fully ready, which unsurprisingly made things harder. At first things were going well: I had a codepen, I reused some ray tracing code made by the amazing Daniel Shiffman for [one of his coding challenges](https://editor.p5js.org/codingtrain/sketches/Nqsq3DFv-), I plugged that on a car that is controlled with the arrow keys, WASD or ZQSD and here we are:
@@ -167,10 +163,10 @@ The evaluation function also has an issue to keep track of laps: It is super imp
At this point I started to frantically code more and more ~~technical debt~~ features in my code:
-- I created some basic cars which trace several rays in front of them, gather average distance on the right and on the left and decide to steer proportionally to these distances. This simple model works surprisingly well. I also wanted to factor the acceleration based on these distances but I didn't get to that and simply made them accelerate more and more for each laps they do.
-- I then made the factors used to steer some random numbers acting as the genes of a genetic algorithm, I created a pool of cars and made them reproduce and mix these genes. At these points the results were not super convincing because my algorithm isn't super well tuned. But I think I validated the basic idea: With a better track generation, a mode decoupled data model I should be able to make a working algorithm.
-- I also tried to use [dannjs](https://dannjs.org/) which is a nice little neural network library. My idea was to train a neural network via neuro-evolution algorithms. I did several tests but I ended up realizing that neural networks aren't that simple and that you still need to study the math underneath to use them properly.
-- I added some broken statistics capabilities to my pool to have an idea of how my cars perform. I'm not convinced my stats are really relevant and I had a big plan of creating real time graphs visualization a bit like the [Primer videos](https://www.youtube.com/c/PrimerLearning) but that didn't happen.
+- I created some basic cars which trace several rays in front of them, gather average distance on the right and on the left and decide to steer proportionally to these distances. This simple model works surprisingly well. I also wanted to factor the acceleration based on these distances but I didn't get to that and simply made them accelerate more and more for each laps they do.
+- I then made the factors used to steer some random numbers acting as the genes of a genetic algorithm, I created a pool of cars and made them reproduce and mix these genes. At these points the results were not super convincing because my algorithm isn't super well tuned. But I think I validated the basic idea: With a better track generation, a mode decoupled data model I should be able to make a working algorithm.
+- I also tried to use [dannjs](https://dannjs.org/) which is a nice little neural network library. My idea was to train a neural network via neuro-evolution algorithms. I did several tests but I ended up realizing that neural networks aren't that simple and that you still need to study the math underneath to use them properly.
+- I added some broken statistics capabilities to my pool to have an idea of how my cars perform. I'm not convinced my stats are really relevant and I had a big plan of creating real time graphs visualization a bit like the [Primer videos](https://www.youtube.com/c/PrimerLearning) but that didn't happen.
### Thinking of the future
diff --git a/src/posts/2021/11/eleventy_search_bar.md b/src/posts/2021/11/eleventy_search_bar.md
index 1036f4273..70304b374 100644
--- a/src/posts/2021/11/eleventy_search_bar.md
+++ b/src/posts/2021/11/eleventy_search_bar.md
@@ -39,6 +39,7 @@ _I am also in the process of adding a `creationDate` field so that I can have mo
Now that the list is available to my templates I created a new nunjucks template to show all my songs:
{% raw %}
+
```jinja2
{% set sortedChords = chords | sortChords | groupby("artist") %}
@@ -62,6 +63,7 @@ Now that the list is available to my templates I created a new nunjucks template
{% endfor %}
```
+
{% endraw %}
There is nothing particularly clever here: In the first line `chords` is the raw data coming from the JSON file. `sortChords` is [an eleventy filter I wrote](https://github.com/statox/blog/blob/83c9fd3/tools/eleventy/filters.js#L96-L103) which sorts the data alphabetically by artist and by title. And the `groupby("artist")` nunjucks [buit-in filter](https://mozilla.github.io/nunjucks/templating.html#groupby) takes all the data and turns it into a map where the keys are the artist names and the values are lists of the items from the json file.
@@ -78,9 +80,9 @@ I'm happy with my list of 500 songs but it's not super easy to navigate: I need
I'm sure there are a lot of clever ways to do that but I decided to go with the inefficient and dirty way:
-- Create a text input;
-- Use its `oninput` property to call a short javascript function;
-- The javascript function will iterate over all the HTML elements and add a `.hidden` CSS class to the ones which don't match the query.
+- Create a text input;
+- Use its `oninput` property to call a short javascript function;
+- The javascript function will iterate over all the HTML elements and add a `.hidden` CSS class to the ones which don't match the query.
#### CSS
@@ -92,13 +94,12 @@ The first easy step is to create the `.hidden` class in a dedicated css file. Wh
}
```
-
#### Input
The input element is super basic too:
```html
-
+
```
I used the `oninput` property instead of `onchange` because I want to see the songs filtered as I type and not when I'm done typing. That makes the search bar more convenient on mobile.
@@ -109,8 +110,8 @@ Before I can create the function to filter the HTML elements I need to bind some
Here I have two types of elements I want to show/hide:
-- The `
` rows which holds the artist and their songs;
-- The `
` items which holds only the song titles.
+- The `
` rows which holds the artist and their songs;
+- The `
` items which holds only the song titles.
And I want the search to act independently on each type of element: If an artist matches my search I want to see all of their songs and I also want to see all of the songs which title matches the search:
@@ -118,13 +119,14 @@ And I want the search to act independently on each type of element: If an artist
To make that work I decided to add different data for each type of element:
-- For both the artist `
` and the song `
` I put in the data attribute the name of the artist;
-- For the artists `
` I add all the concatenated titles of their songs;
-- For the song `
` I add only the song title;
+- For both the artist `
` and the song `
` I put in the data attribute the name of the artist;
+- For the artists `
` I add all the concatenated titles of their songs;
+- For the song `
` I add only the song title;
I put all of this data in a `data-values` attribute and I used nunjucks loops once again to concatenate what needs to be concatenated. I also add a `;` separator between each value so that I'm sure the search will not overlap two different entries:
{% raw %}
+
```jinja2
{% set sortedChords = chords | sortChords | groupby("artist") %}
@@ -148,6 +150,7 @@ I put all of this data in a `data-values` attribute and I used nunjucks loops on
{% endfor %}
```
+
{% endraw %}
I also added a CSS class `datarow` to both the `
` and `
`. This is the selector I'll be using in my javascript to find the elements I need to manipulate in my page.
@@ -184,9 +187,9 @@ And here we have a working search bar which you can try live [on this page]({{'/
It doesn't take an experienced web developer to see that this solution has its flaws:
-- I think that adding all this data in the data attributes increases the size of the page which is probably not great for loading times;
-- The search algorithm is quite dumb and it scans all the elements in the page, using a more efficient data structure would improve the performances;
-- I'm really not sure how this would scale with a list 10x or 100x bigger.
+- I think that adding all this data in the data attributes increases the size of the page which is probably not great for loading times;
+- The search algorithm is quite dumb and it scans all the elements in the page, using a more efficient data structure would improve the performances;
+- I'm really not sure how this would scale with a list 10x or 100x bigger.
But for my specific use case this is working fine and as it took me ~10 years to create the list of 500 songs I don't think the size will become an issue before many more years. Also I'm fairly confident that I'd be able to reuse these pieces of code to create other search bar on my site: All I need is to have html elements with the class `.datarow` and some data to filter in their `data-value` attributes.
diff --git a/src/posts/2021/11/eleventy_secrets.md b/src/posts/2021/11/eleventy_secrets.md
index 8ad22debb..358ab9ba0 100644
--- a/src/posts/2021/11/eleventy_secrets.md
+++ b/src/posts/2021/11/eleventy_secrets.md
@@ -8,30 +8,28 @@ commentIssueId: 30
This blog is a platform for me to experiment with front end technologies and to write about random stuff I do on my free time. I keep everything versioned [on Github](https://www.github.com/statox/blog) in a public repository because it's easy and because so far I didn't have anything to keep secret in this repo. This changed recently so I decided to use [`EncFS`](https://vgough.github.io/encfs/) to keep secret files encrypted in my Github repo and have them easily accessible on my local copy of the repo. Here is how I did it.
-
### Context and requirements
Recently I started to collect pieces of wisdom I hear at my workplace. I intend to share this knowledge in some form because I believe it could be useful to a lot of my peers, but so far I'm not sure how I will do that so I want to keep track of them somewhere and this blog's repo is an easy place. So I started writing a couple of them in a draft and I also wrote the name of the coworkers who gave me these pieces of advice. Before I committed the document I realized that I was about to publish some personal thoughts of people I really appreciate and respect without asking for their consent, not cool.
So here is what I wanted to have:
-- The ability to create new "secret" pages on this blog like I do with any other article.
-- They should be easily accessible on my local clone and they should be handled by eleventy on my local build.
-- They should not be built by eleventy on the CI I use to deploy the blog.
-- They should be versioned in the repo so that I don't have to keep track of data on different places.
-- The solution should work on Linux and I don't really care about the other OSes as I don't use them (though my solution also works on MacOS)
+- The ability to create new "secret" pages on this blog like I do with any other article.
+- They should be easily accessible on my local clone and they should be handled by eleventy on my local build.
+- They should not be built by eleventy on the CI I use to deploy the blog.
+- They should be versioned in the repo so that I don't have to keep track of data on different places.
+- The solution should work on Linux and I don't really care about the other OSes as I don't use them (though my solution also works on MacOS)
To do that I opted for the following solution:
-- I will have a `src/.secrets` directory in my repo. This directory will hold my secret files encrypted.
-- I will have another directory `src/secrets/` in which the secrets will be decrypted when I build the site locally, eleventy will have to build this directory too.
-- To make things easy I will have the decryption script running in the CI I use locally when building my site.
+- I will have a `src/.secrets` directory in my repo. This directory will hold my secret files encrypted.
+- I will have another directory `src/secrets/` in which the secrets will be decrypted when I build the site locally, eleventy will have to build this directory too.
+- To make things easy I will have the decryption script running in the CI I use locally when building my site.
**An important warning**
**The solution I'm presenting here is dealing with very low importance documents. I don't plan to store any applications secrets like an API key or any sensitive document. So while I'm confident this solution fits my threat model I am in no way encouraging you to use it in production without a proper review of your risks.**
-
### The tool
I'll be using [`EncFS`](https://vgough.github.io/encfs/) a tool providing an encrypted file system in the user space: It translates the file system operations one would be doing into the equivalent encrypted operations on the file system.
@@ -88,9 +86,9 @@ encfs "${PWD}/$SECRET_DIR" "${PWD}/$CLEAR_DIR"
This script will run when I build my site locally so it does the following:
-- Check that the clear directory is empty. If it's not it means that I had already mounted the secret directory (e.g. I restarted the build process because something broke it) so I can skip what's next.
-- Create the clear directory if needed.
-- Use `encfs` to mount the decrypted directory.
+- Check that the clear directory is empty. If it's not it means that I had already mounted the secret directory (e.g. I restarted the build process because something broke it) so I can skip what's next.
+- Create the clear directory if needed.
+- Use `encfs` to mount the decrypted directory.
```bash
# unmount_secrets.sh
@@ -102,7 +100,6 @@ fusermount -u "${PWD}/$CLEAR_DIR"
This one is not in my local CI. I use it when I'm done working to unmount the clear directory.
-
### Configuring my build
With the `decrypt_secrets.sh` wrapper created I can update my `package.json`:
@@ -119,28 +116,27 @@ With the `decrypt_secrets.sh` wrapper created I can update my `package.json`:
So now when I use `npm run dev` in my local environment my decryption script is run. However when my CI on Github runs `npm run build` my secrets are not touched.
-
### Setting up the ignores
There is one last piece of configuration to add: the ignored files. Until now I only had a `.gitignore` file in my repo with two purposes:
-- It prevented me to track changes in `node_modules/` and `docs/` (my local build file)
-- And it also prevented eleventy to try to build these directories.
+- It prevented me to track changes in `node_modules/` and `docs/` (my local build file)
+- And it also prevented eleventy to try to build these directories.
Now I have a new directory `src/secrets` which I want eleventy to build (locally) but I don't want to track on git (since that would completely defeat the purpose of all this encryption thing I've been doing).
So I had to do the following:
-- First tell eleventy to not use the `.gitignore` file. This is done by adding this to my `.eleventy.js` config file. Now git will still respect `.gitignore` but eleventy will use the `.eleventyignore` file to exclude files from the build.
+- First tell eleventy to not use the `.gitignore` file. This is done by adding this to my `.eleventy.js` config file. Now git will still respect `.gitignore` but eleventy will use the `.eleventyignore` file to exclude files from the build.
- eleventyConfig.setUseGitIgnore(false);
+ eleventyConfig.setUseGitIgnore(false);
-- Then my `.gitignore` remains untouched
-- And finally I added `.eleventyignore` with the following content:
+- Then my `.gitignore` remains untouched
+- And finally I added `.eleventyignore` with the following content:
- node_modules/
- docs/
- src/secrets/
+ node_modules/
+ docs/
+ src/secrets/
### Voila!
diff --git a/src/posts/2022/03/dockerizing_dev_env.md b/src/posts/2022/03/dockerizing_dev_env.md
index f5aa76b64..23bcf9174 100644
--- a/src/posts/2022/03/dockerizing_dev_env.md
+++ b/src/posts/2022/03/dockerizing_dev_env.md
@@ -74,6 +74,7 @@ docker exec -ti provitools sh -c "python --version"
Adding docker compose (maybe too early but at least it will be there)
`docker-compose.yml`
+
```dockerfile
version: '3.7'
@@ -84,6 +85,7 @@ services:
```
`build.sh`
+
```shell
#!/usr/bin/env bash
sudo docker build . -t provisioning/tools
@@ -91,6 +93,7 @@ sudo docker-compose build
```
`start.sh`
+
```shell
#!/usr/bin/env bash
sudo docker-compose up -d
@@ -154,7 +157,6 @@ RUN pip install -r pip_requirements.txt
ENTRYPOINT ["tail", "-f", "/dev/null"]
```
-
### Step 6
We can run ansible playbook. And (somehow?) `aws` is installed on the container 🤷
@@ -186,5 +188,3 @@ I added `-e SSH_AUTH_SOCK=$SSH_AUTH_SOCK` to my alias but the directory is rando
So I need to fix that.
[This](https://www.jamesridgway.co.uk/sharing-an-ssh-agent-between-a-host-machine-and-a-docker-container/) provides a solution but my `SSH_AUTH_SOCK` variable is empty
-
-
diff --git a/src/posts/2022/04/updates_04_22.md b/src/posts/2022/04/updates_04_22.md
index 821d859d0..42c279c1c 100644
--- a/src/posts/2022/04/updates_04_22.md
+++ b/src/posts/2022/04/updates_04_22.md
@@ -36,16 +36,15 @@ With that I also got two buddies of mine to regularly play music together: We tr
I also try to play with more people, so I've been playing with a couple of teammates at Dashlane this is very casual but it was the opportunity to see that I _can_ play with other people which I'm pretty happy about!
-
### Making this site useful
So I'm playing music but I'm still a nerd and what's better than when two of your hobbies come together?
I decided to use this site I'm creating to be a useful resource when I'm playing. So I added several sections:
-- I worked a lot on my [chords](/chords) page. I use it to list all the chords of the songs I can play so I worked on a clean presentation which works on desktop and mobile and is convenient to search. I added a "Random song" button to avoid playing always the same songs as well as a list of the last songs I added. What I'm at the same time the most proud of and the most ashamed of is the "poor's man CRM" system I created: I use a Github workflow on the repo of this website to monitor a specific issue of the repo and transform my comments into JSON data that is then committed to my list of chords. This is not super clean but I think it's a creative and easy way to ease my life. I want to write about that at some point.
+- I worked a lot on my [chords](/chords) page. I use it to list all the chords of the songs I can play so I worked on a clean presentation which works on desktop and mobile and is convenient to search. I added a "Random song" button to avoid playing always the same songs as well as a list of the last songs I added. What I'm at the same time the most proud of and the most ashamed of is the "poor's man CRM" system I created: I use a Github workflow on the repo of this website to monitor a specific issue of the repo and transform my comments into JSON data that is then committed to my list of chords. This is not super clean but I think it's a creative and easy way to ease my life. I want to write about that at some point.
-- On the [music](/music) page I also added different sections. One with all the online resources I'm using to learn music theory. This is not super convenient to use and I'm still thinking out how I want to rework it. And another sections with the manuals and default settings of the pedals I own. This page too is more a first try of something that I want to improve in the future.
+- On the [music](/music) page I also added different sections. One with all the online resources I'm using to learn music theory. This is not super convenient to use and I'm still thinking out how I want to rework it. And another sections with the manuals and default settings of the pedals I own. This page too is more a first try of something that I want to improve in the future.
So now when I setup myself to play some guitar I can pull my site and have everything I need right at my fingertips! I'm happy with that because I think making things which make your life easier is what the internet and technology is all about.
@@ -63,23 +62,22 @@ I have also started 3 different articles for this website that I never finished
When I'm not playing music and tweaking this website I also keep practicing my useless side projects! Since November I have worked on several projects which are in the [project](/project) page:
-- I implemented an ["instrument"](https://codepen.io/statox/full/qBPwaNo) with p5js. The idea was to experiment with the MIDI capabilities of the library with a dumb project. I am not completely convinced by what I've seen and I think in the future I will experiment with other musical JS library to see what I can gete out of them.
-- In December I did the advent of code. Stopping at day 14 which is two day earlier than in 2020.
-- To help me learn music scales I implemented the [chord wheel](https://statox.github.io/chord-wheel/) which is originally a paper tool coming from a book that I've turned into a web page. It would probably deserve a full rewrite to be better organized, bugfree and allow to implement other similar tools (like the "circle of fiths"), again: maybe later...
-- At Dashlane I've been revamping the exercise that we use to interview our candidates and following my usual hobbies I came up with a exercise based on cellular automata. So that was a good excuse to implement some new ones! First I made a simple [Langton's Ant](https://statox.github.io/pixijs-langton-ant/) which is not super impressive but was fun to do. I twisted it a bit by coloring the sections created by the pattern. On this project I used pixijs to try alternatives to p5js, that was a long time ago, I didn't write about it and my memory doesn't serve me well but I'd say it wasn't a great experience because otherwise I would have tried it in another project.
-- And while I was thinking of cellular automata I finally implemented a 1D automata platform for the first time! I called the project [circular automata](https://github.com/statox/circular-automata/) because my initial thought was to represent a classical automata with concentric circles. The implementation of the automata was quite simple and the visualization too but this project got super interesting when I decided to use sveltejs in it. With svelte I created a super convenient architecture where I can have one component to run the p5js animation and dedicated components to control the simulation. This component system allows me to easily plug new visualizations, or to test new graphic frameworks (I'm currently experimenting with a threejs component). I think setting up my first project with p5 and svelte is a major break through in my side project as it should allow me to be faster to create well architectured, more complete and more convenient projects, so I'm looking forward to have more time to do new experiments.
-- In a completely different area I also finally created my [setup repository](https://github.com/statox/setup). This is something I had been wanting to do for many many years but when my Dashlane computer broke and I had to reinstall of my setup I decided it was the final straw. The great thing is that at Dashlane I have had the opportunity to work a lot with Ansible and to better understand how it is supposed to work and to be used. Also a teammate of mine kindly let me look into his own repository of Ansible playbooks and that got me started. Now I have a collection of playbooks which allow me to setup most of my common tools of a Linux machine from the Desktop environment, to my favorite packages and configurations, to my own dotfiles. This is a project which will keep growing and that I'll need to evolve regularly like [my dotfiles](https://github.com/statox/dotfiles) but it's incredibly satisfying to use. I'm also evolving it to handle my different server setups like my OVH box or my local raspberry!
-- And I also created a script which scraps [Nasa's Astronomy picture of the day](https://apod.nasa.gov/) every day and sets it up as my desktop background as well as my Zoom virtual background. I intended to write an article about that because Zoom doesn't allow to you programmatically change your background and I was happy to find a solution but I haven't found the motivation to do it yet
+- I implemented an ["instrument"](https://codepen.io/statox/full/qBPwaNo) with p5js. The idea was to experiment with the MIDI capabilities of the library with a dumb project. I am not completely convinced by what I've seen and I think in the future I will experiment with other musical JS library to see what I can gete out of them.
+- In December I did the advent of code. Stopping at day 14 which is two day earlier than in 2020.
+- To help me learn music scales I implemented the [chord wheel](https://statox.github.io/chord-wheel/) which is originally a paper tool coming from a book that I've turned into a web page. It would probably deserve a full rewrite to be better organized, bugfree and allow to implement other similar tools (like the "circle of fiths"), again: maybe later...
+- At Dashlane I've been revamping the exercise that we use to interview our candidates and following my usual hobbies I came up with a exercise based on cellular automata. So that was a good excuse to implement some new ones! First I made a simple [Langton's Ant](https://statox.github.io/pixijs-langton-ant/) which is not super impressive but was fun to do. I twisted it a bit by coloring the sections created by the pattern. On this project I used pixijs to try alternatives to p5js, that was a long time ago, I didn't write about it and my memory doesn't serve me well but I'd say it wasn't a great experience because otherwise I would have tried it in another project.
+- And while I was thinking of cellular automata I finally implemented a 1D automata platform for the first time! I called the project [circular automata](https://github.com/statox/circular-automata/) because my initial thought was to represent a classical automata with concentric circles. The implementation of the automata was quite simple and the visualization too but this project got super interesting when I decided to use sveltejs in it. With svelte I created a super convenient architecture where I can have one component to run the p5js animation and dedicated components to control the simulation. This component system allows me to easily plug new visualizations, or to test new graphic frameworks (I'm currently experimenting with a threejs component). I think setting up my first project with p5 and svelte is a major break through in my side project as it should allow me to be faster to create well architectured, more complete and more convenient projects, so I'm looking forward to have more time to do new experiments.
+- In a completely different area I also finally created my [setup repository](https://github.com/statox/setup). This is something I had been wanting to do for many many years but when my Dashlane computer broke and I had to reinstall of my setup I decided it was the final straw. The great thing is that at Dashlane I have had the opportunity to work a lot with Ansible and to better understand how it is supposed to work and to be used. Also a teammate of mine kindly let me look into his own repository of Ansible playbooks and that got me started. Now I have a collection of playbooks which allow me to setup most of my common tools of a Linux machine from the Desktop environment, to my favorite packages and configurations, to my own dotfiles. This is a project which will keep growing and that I'll need to evolve regularly like [my dotfiles](https://github.com/statox/dotfiles) but it's incredibly satisfying to use. I'm also evolving it to handle my different server setups like my OVH box or my local raspberry!
+- And I also created a script which scraps [Nasa's Astronomy picture of the day](https://apod.nasa.gov/) every day and sets it up as my desktop background as well as my Zoom virtual background. I intended to write an article about that because Zoom doesn't allow to you programmatically change your background and I was happy to find a solution but I haven't found the motivation to do it yet
### Staying healthy
Another huge change I have experienced other the last 6 months is that I realized I actually like doing sport. Ever since I was a kid I have never felt particularly attracted by sports (despite doing fencing for close to 10 years 🤷) and I blame the French school system for that (I should write about it one day, maybe that would be more interesting than my random coding adventures). But since December I'm taking yoga classes and I'm loving it!
-I think I'm lucky because I found a great setup where I can do yoga with people I love which is super motivating but I also dared taking classes by myself! I have really enjoyed getting into this yoga thing I knew nothing about, learning the different types of yoga, trying to understand the meaning and the origin of this practice, figuring out what I like and what I don't... So know I can have a conversation about Yoga and I've been going (almost) every week for the past 4 months which I'm really proud about. Maybe at one point I'll actually start to feel physical benefits but at least for now it's a good mental health thing to do!
+I think I'm lucky because I found a great setup where I can do yoga with people I love which is super motivating but I also dared taking classes by myself! I have really enjoyed getting into this yoga thing I knew nothing about, learning the different types of yoga, trying to understand the meaning and the origin of this practice, figuring out what I like and what I don't... So know I can have a conversation about Yoga and I've been going (almost) every week for the past 4 months which I'm really proud about. Maybe at one point I'll actually start to feel physical benefits but at least for now it's a good mental health thing to do!
I'm also looking into getting enrolled in a mentoring program for young people who struggle finding a job, I'm still figuring out the details but it might be a great way to give back what life gave me which would be quite cool.
-
### I'm doing well
So yeah if I reflect on the past 6 months I've been doing stuff, I think I'm pretty happy, I have great stuff going on at work and in my personal life too that I won't write about here and the weather is getting great again! Life is good.
diff --git a/src/posts/2024/04/api_logging_elasticsearch/index.md b/src/posts/2024/04/api_logging_elasticsearch/index.md
index 51dae7120..fe6aff13c 100644
--- a/src/posts/2024/04/api_logging_elasticsearch/index.md
+++ b/src/posts/2024/04/api_logging_elasticsearch/index.md
@@ -8,54 +8,51 @@ commentIssueId: 36
Notes about how I set up an [OpenSearch](https://docs.aws.amazon.com/opensearch-service/) cluster to manage the logs of [my api](https://github.com/statox/api.statox.fr).
-Goal: Set up the cheapest ELK cluster possible to
- - Ingest the logs of my API
- - Maybe use as a tracking database for my habits
+Goal: Set up the cheapest ELK cluster possible to - Ingest the logs of my API - Maybe use as a tracking database for my habits
TODO:
-- Review costs after some usage. The idea was to benefit from the free tier, after one week it seems I don't get it.
-- Review [UltraWarm](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ultrawarm.html) nodes they might be usefull for my usage if I can't benefit from the free tier.
-
+- Review costs after some usage. The idea was to benefit from the free tier, after one week it seems I don't get it.
+- Review [UltraWarm](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/ultrawarm.html) nodes they might be usefull for my usage if I can't benefit from the free tier.
## Setup the cluster in AWS
Everything done easily from the AWS console. I had to use "Standard create" to be able to setup a smaller cluster than what AWS recommends because I have very small needs.

+
Using a single node both for master and data with the smallest possible EBS and minimum IOPS.
-
I also set up a custom endpoint so that I can reach my cluster from logs.statox.fr instead of the default long endpoint provided by ELK. The setup is simple: Create a certicate in ACM, setup a DNS verification to validate the certificate and use the certificate in the setup screen of OpenSearch.
-
-The security is far from ideal but pretty convenient for a very-not-critical API like mine: The cluster is open to internet and the auth is done with ELK's built-in user store. (Note that the automatic software updates are enabled thank to the managed aspect of the cluster, I'll need to make sure it doesn't break stuff when I don't do anything).
+The security is far from ideal but pretty convenient for a very-not-critical API like mine: The cluster is open to internet and the auth is done with ELK's built-in user store. (Note that the automatic software updates are enabled thank to the managed aspect of the cluster, I'll need to make sure it doesn't break stuff when I don't do anything).

+
Using a single node both for master and data with the smallest possible EBS and minimum IOPS.
-

+
TODO: Check if I can better restrict this policy.
-
By default the cluster has hourly snapshots. The cluster takes several minutes to start up, once it is up we can test that it answers properly:
```bash
@@ -93,9 +90,9 @@ This is the template of settings which will be applied to all the indices which
Important settings:
-- Specify that we are working with data streams
-- Specify the `timestamp` field as the time field (which will allow the proper indexing and temporal search).
-- We are not really using index pattern as with regular indices because we are using a data stream, so the `index pattern` property must have the name of the stream we will create later on. _Note: No * character_
+- Specify that we are working with data streams
+- Specify the `timestamp` field as the time field (which will allow the proper indexing and temporal search).
+- We are not really using index pattern as with regular indices because we are using a data stream, so the `index pattern` property must have the name of the stream we will create later on. _Note: No \* character_

@@ -107,7 +104,6 @@ The index mapping are useful to specify that a specific field is not a simple nu

-
### 2. Create the data stream
If created with the name used in the index template's `index pattern` field the stream will be associated to the template.
@@ -121,7 +117,6 @@ curl -H 'Content-Type: application/json' -XPOST --user "$ELASTIC_USER:$ELASTIC_
-d '{"message": "Test message from bash", "timestamp": $(date +"%s")000}' # With a shitty hack to transform seconds to milliseconds
```
-
### 3. Create the Index pattern
This is the entity which tells to Dashboards (Kibana) which indices to search when you are in the `Dicover` tab.
@@ -139,19 +134,16 @@ From there the logs are available in the `Discover` tab:
This is the final step to make sure the indices backing the data streams are regularly rotated (so that at one point they can be deleted to keep the volume of data below a certain threshold without dropping a unique index with all the logs).
-
An optional step 1 is to setup a Notification channel to be notified when the policy fails, settings up a notification on a slack webhook is super straight forward, just past the webhook URL and you're done.
-

By using the correct index pattern, the policy will be applied to all the indices of the data stream and will rollover them.
-
## Conclusion
This kind of setup is something I'm used to do on a much bigger scale in my day job so I see the cracks in this current setup but at least it's working conveniently for my small needs.
-- It would be great to terraform the AWS part (but, _la flemme_)
-- I need to check if I can easily restore the automatic snapshots made by AWS and if that keeps the configurations I did in Kibana (in theory, yes)
-- Next I'll use this document store as part of the product of my api.
+- It would be great to terraform the AWS part (but, _la flemme_)
+- I need to check if I can easily restore the automatic snapshots made by AWS and if that keeps the configurations I did in Kibana (in theory, yes)
+- Next I'll use this document store as part of the product of my api.
diff --git a/src/posts/2024/04/github_dependabot_auto_merge/index.md b/src/posts/2024/04/github_dependabot_auto_merge/index.md
index 20b1f1971..a7d24c4fa 100644
--- a/src/posts/2024/04/github_dependabot_auto_merge/index.md
+++ b/src/posts/2024/04/github_dependabot_auto_merge/index.md
@@ -31,13 +31,13 @@ Allow Dependabot to regularly create PRs with dependencies update.
In the Github repo settings: Security > Code security and analysis > Dependabot

+
Enable the Dependabot alerts
For better configuration a file `github/dependabot.yml` can be created in the repo, see [the doc](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file) for more details.
-
### Actions settings
Allow GitHub Actions to create and approve pull requests. This is needed because the workflow we will trigger will be responsible for approving the PR automatically.
@@ -45,6 +45,7 @@ Allow GitHub Actions to create and approve pull requests. This is needed because
In the Github repo settings: Code and automation > Actions > General > Workflow permissions

+
Enable the actions to modify PRs
@@ -57,15 +58,15 @@ The rule needs to apply to the `main` branch (i.e. the one we'll be merging to).
We need two checks enforced by the rule:
-- `Require a pull request before merging` and `Require approvals`: The approval will be given by `github-action` bot throught the workflow
-- `Require status checks to pass before merging`: The checks will be the success of the workflow itself and we'll make the workflow fail if the tests for the repo are not validated.
+- `Require a pull request before merging` and `Require approvals`: The approval will be given by `github-action` bot throught the workflow
+- `Require status checks to pass before merging`: The checks will be the success of the workflow itself and we'll make the workflow fail if the tests for the repo are not validated.

+
Enforce PR approval and checks
-
## Setup the workflow
In the repo create a file for the workflow like `.github/workflows/dependabot-auto-merge.yml`
@@ -76,15 +77,15 @@ We will trigger the workflow on PRs.
**TODO** Find a way to trigger only for dependabot PRs, for now all MR will be automatically merged if they pass the tests.
-- `types`: Using `edited` is useful to debug the workflow while setting it up: once the MR is open, you can edit the workflow, push, comment `@dependabot rebase` on the PR and the workflow will be re-run
+- `types`: Using `edited` is useful to debug the workflow while setting it up: once the MR is open, you can edit the workflow, push, comment `@dependabot rebase` on the PR and the workflow will be re-run
```yaml
name: Test and AutoMerge PRs
on:
- pull_request:
- types: [opened, synchronize, edited]
- branches: [main]
+ pull_request:
+ types: [opened, synchronize, edited]
+ branches: [main]
```
### Permissions
@@ -93,16 +94,16 @@ This changes the permissions of the github token that dependabot gets when creat
```yaml
permissions:
- # This is needed to approve the PR
- pull-requests: write
- # This is needed to merge the PR https://github.com/cli/cli/issues/6695#issuecomment-1348430969
- contents: write
+ # This is needed to approve the PR
+ pull-requests: write
+ # This is needed to merge the PR https://github.com/cli/cli/issues/6695#issuecomment-1348430969
+ contents: write
```
Without these permissions the calls the the `gh` cli in the next steps fail with errors similar to this:
-

+
Example of gh permission error
@@ -113,24 +114,23 @@ One way to have the whole workflow triggered only for dependabot's PR is to add
```yaml
jobs:
- test-and-auto-merge:
- if: github.actor == 'dependabot[bot]'
- runs-on: ubuntu-latest
- steps:
- # [...]
+ test-and-auto-merge:
+ if: github.actor == 'dependabot[bot]'
+ runs-on: ubuntu-latest
+ steps:
+ # [...]
```
This could be improved to better factorize the code and have the tests running on all MR and the auto merge running only on dependabot PRs but since I'm the only one working on this repo and I don't use PRs for other reasons I will not bother with that.
-
### Repo setup and tests
This is dependent on all repos though the important part is to run some tests. Here we need several setup steps:
-- Install `python` throught a marketplace Github action to be able to install `podman-compose` with `pip`
-- Install `podman` throught a marketplace Github action.
-- Install `node` to run build the project and run the tests.
-- Checkout the code, install the deps and run the tests.
+- Install `python` throught a marketplace Github action to be able to install `podman-compose` with `pip`
+- Install `podman` throught a marketplace Github action.
+- Install `node` to run build the project and run the tests.
+- Checkout the code, install the deps and run the tests.
If these steps fail the following one will fail too, so the PRs tests will fail and the code will not be merged.
@@ -177,9 +177,9 @@ jobs:
Three important steps:
-- Call the `fetch-metadata` action to get the `$PR_URL` variable referring to the current PR and used in the next steps.
-- Have the `github-action` bot approve the PR
-- Have the `github-action` bot set the `auto merge` setting for the PR, which will trigger the merge of the PR because all the checks will succeed.
+- Call the `fetch-metadata` action to get the `$PR_URL` variable referring to the current PR and used in the next steps.
+- Have the `github-action` bot approve the PR
+- Have the `github-action` bot set the `auto merge` setting for the PR, which will trigger the merge of the PR because all the checks will succeed.
```yaml
jobs:
@@ -214,18 +214,19 @@ jobs:
Once all of that is configured the Dependabot PRs should be automatically handled.

+
The check tab of the PR should have some results
-

+
The checks should point to a succesful action
-

+
The various bots should have acted on the PR
diff --git a/src/posts/posts.md b/src/posts/posts.md
index b911fcea3..bb278dc82 100644
--- a/src/posts/posts.md
+++ b/src/posts/posts.md
@@ -1,7 +1,6 @@
---
layout: layouts/posts.njk
eleventyNavigation:
- key: Posts
- order: 2
+ key: Posts
+ order: 2
---
-
diff --git a/src/todo/circular_jump.md b/src/todo/circular_jump.md
index e320d7375..3b264e341 100644
--- a/src/todo/circular_jump.md
+++ b/src/todo/circular_jump.md
@@ -13,12 +13,11 @@ The track should be circular.
The player starts at an angle of 0 and the goal is to make as many full cycles as possible.
The progress detection could be:
- - Start at angle 0
- - On each frame check the current angle
- - If it's larger than the previous max value update it
- - If it's larger than 2 pi, add 1 turn to the counter and reset with the difference to zero
- - Make sure to handle <0 angle to avoid counting "reverse" turns
-
+- Start at angle 0
+- On each frame check the current angle
+ - If it's larger than the previous max value update it
+ - If it's larger than 2 pi, add 1 turn to the counter and reset with the difference to zero
+ - Make sure to handle <0 angle to avoid counting "reverse" turns
The obstacles could be generated either from the angle 0 or directly behind the player and starting in the opposite direction.
diff --git a/src/todo/homemade_monitoring.md b/src/todo/homemade_monitoring.md
index 1ff01dfc2..ac35ed1de 100644
--- a/src/todo/homemade_monitoring.md
+++ b/src/todo/homemade_monitoring.md
@@ -9,6 +9,6 @@ Goal: Setup a cheap monitoring and alerting platform for my personal infrastruct
Things to monitor:
- - Pihole
- - This website
- - Backups from my NAS
+- Pihole
+- This website
+- Backups from my NAS
diff --git a/src/todo/todo_page.md b/src/todo/todo_page.md
index 0a415ea47..ee2716220 100644
--- a/src/todo/todo_page.md
+++ b/src/todo/todo_page.md
@@ -7,6 +7,6 @@ title: Todo page on the blog
This page is a work in progress that I want to finish.
-- [ ] Rework the UI to better show the items (for now it is mostly based on the notes layouts)
-- [X] Add the ability to add an entry from a Github issue like it's done with the chords
-- [ ] Add sort and search features (by name, content and tags)
+- [ ] Rework the UI to better show the items (for now it is mostly based on the notes layouts)
+- [x] Add the ability to add an entry from a Github issue like it's done with the chords
+- [ ] Add sort and search features (by name, content and tags)
diff --git a/src/todo/weather_station.md b/src/todo/weather_station.md
index 943e842b8..370cf09bb 100644
--- a/src/todo/weather_station.md
+++ b/src/todo/weather_station.md
@@ -9,7 +9,7 @@ Goal: Setup a weather monitoring system for the house.
Components:
- - Multiple temperature, humidity and air quality sensors across the house
- - Probably running on arduino nano or raspberry-pi zero
- - A centralized server getting the data from the sensors
- - A monitoring system with history of the data
+- Multiple temperature, humidity and air quality sensors across the house
+ - Probably running on arduino nano or raspberry-pi zero
+- A centralized server getting the data from the sensors
+- A monitoring system with history of the data
diff --git a/src/user_manuals/index.md b/src/user_manuals/index.md
index f7f46cc69..8720bc783 100644
--- a/src/user_manuals/index.md
+++ b/src/user_manuals/index.md
@@ -8,36 +8,36 @@ Some user manuals I have collected over time and might need in the future.
### Pedals Manuals
-- [Behringer BO100](https://mediadl.musictribe.com/media/sys_master/hed/h3f/8850084069406.pdf) (_[mirror](/pdf/pedal_user_manuals/behringer_bo100_user_manual.pdf)_)
-- [Boss BD2](https://static.roland.com/assets/media/pdf/BD-2_eng02_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_bd2_user_manual.pdf)_)
-- [Boss CH1](https://static.roland.com/assets/media/pdf/CH-1_M_eng03_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_ch1_user_manual.pdf)_)
-- [Boss OC3](https://static.roland.com/assets/media/pdf/OC-3_e01_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_oc3_user_manual.pdf)_)
-- [Boss RC3](https://static.roland.com/assets/media/pdf/RC-3_eng03_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_rc3_user_manual.pdf)_)
-- [Boss RC10-R](https://static.roland.com/assets/media/pdf/RC-10R_eng03_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_rc10r_user_manual.pdf)_)
-- [Donner MiniPedal Dark Mouse](https://cdn.shopify.com/s/files/1/1384/9629/files/EC1178_Dark_Mouse__Manual_V02_190809.pdf?v=1597289663) (_[mirror](/pdf/pedal_user_manuals/donner_dark_mouse_manual.pdf)_)
-- [Electro-Harmonix Canyon](https://www.ehx.com/wp-content/uploads/2021/01/canyon-manual.pdf) (_[mirror](/pdf/pedal_user_manuals/ehx_canyon_manual.pdf)_)
-- [EarthQuaker Devices Afterneath](https://static1.squarespace.com/static/57cebe2c03596e075fca5f24/t/656fc46102d950061c2b9d06/1701823585949/EQD-Afterneath-Manual-R2-WEB.pdf) (_[mirror](/pdf/pedal_user_manuals/eqd_afterneath_manual.pdf)_)
-- [Peterson StroboStomp HD tuner](https://www.petersontuners.com/media/pdf/StroboStomp_HD_Manual_v1.1_EN.pdf) (_[mirror](/pdf/pedal_user_manuals/StroboStomp_HD_Manual_v1.1_EN.pdf)_)
-- [ZVEX Instant Lofi Junky](https://static1.squarespace.com/static/555e332ce4b0577e788c3a16/t/559efae5e4b0da93269a9ffb/1436482277079/ZVEX+Instant+Lo-Fi+Junky+Instructions.pdf) (_[mirror](/pdf/pedal_user_manuals/zvex_instant_lofi_junky_user_manual.pdf)_)
+- [Behringer BO100](https://mediadl.musictribe.com/media/sys_master/hed/h3f/8850084069406.pdf) (_[mirror](/pdf/pedal_user_manuals/behringer_bo100_user_manual.pdf)_)
+- [Boss BD2](https://static.roland.com/assets/media/pdf/BD-2_eng02_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_bd2_user_manual.pdf)_)
+- [Boss CH1](https://static.roland.com/assets/media/pdf/CH-1_M_eng03_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_ch1_user_manual.pdf)_)
+- [Boss OC3](https://static.roland.com/assets/media/pdf/OC-3_e01_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_oc3_user_manual.pdf)_)
+- [Boss RC3](https://static.roland.com/assets/media/pdf/RC-3_eng03_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_rc3_user_manual.pdf)_)
+- [Boss RC10-R](https://static.roland.com/assets/media/pdf/RC-10R_eng03_W.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_rc10r_user_manual.pdf)_)
+- [Donner MiniPedal Dark Mouse](https://cdn.shopify.com/s/files/1/1384/9629/files/EC1178_Dark_Mouse__Manual_V02_190809.pdf?v=1597289663) (_[mirror](/pdf/pedal_user_manuals/donner_dark_mouse_manual.pdf)_)
+- [Electro-Harmonix Canyon](https://www.ehx.com/wp-content/uploads/2021/01/canyon-manual.pdf) (_[mirror](/pdf/pedal_user_manuals/ehx_canyon_manual.pdf)_)
+- [EarthQuaker Devices Afterneath](https://static1.squarespace.com/static/57cebe2c03596e075fca5f24/t/656fc46102d950061c2b9d06/1701823585949/EQD-Afterneath-Manual-R2-WEB.pdf) (_[mirror](/pdf/pedal_user_manuals/eqd_afterneath_manual.pdf)_)
+- [Peterson StroboStomp HD tuner](https://www.petersontuners.com/media/pdf/StroboStomp_HD_Manual_v1.1_EN.pdf) (_[mirror](/pdf/pedal_user_manuals/StroboStomp_HD_Manual_v1.1_EN.pdf)_)
+- [ZVEX Instant Lofi Junky](https://static1.squarespace.com/static/555e332ce4b0577e788c3a16/t/559efae5e4b0da93269a9ffb/1436482277079/ZVEX+Instant+Lo-Fi+Junky+Instructions.pdf) (_[mirror](/pdf/pedal_user_manuals/zvex_instant_lofi_junky_user_manual.pdf)_)
### Others Manuals
-- Amp [Laney LA35C acoustic](https://www.zikinf.com/manuels/laney-la35c-manuel-utilisateur-en-28749.pdf) (_[mirror](/pdf/laney-la35c.pdf)_)
-- Amp [Marshall Valvestate 8040 (and similar 8xxx series)](https://manualzz.com/download/8600586) (_[mirror](/pdf/marshall-valvestate.pdf)_)
-- Guitar Fender Telecaster American Pro II
- - [User manual](https://www.fmicassets.com/Damroot/Original/10001/Fender_ElectricGuitars_Manual.pdf) (_[mirror](/pdf/Fender_ElectricGuitars_Manual.pdf)_)
- - [Service manual](https://www.fmicassets.com/Damroot/Original/10001/SM_011394XXXX_Am_Pro_II_Telecaster.pdf) (_[mirror](/pdf/SM_011394XXXX_Am_Pro_II_Telecaster.pdf)_)
-- [Lottie Canto - Colour Palette](/pdf/lottie_canto_colour_palette.pdf)
-- Midi Controller [Akai MPK mini mk3](https://cdn.inmusicbrands.com/akai/mpk3mini/MPK-mini-Quickstart-Guide-v1_3.pdf) (_[mirror](/pdf/Akai_mpk_mini_mk3_quickstart_guide_v1_3.pdf)_)
-- Roland Aira Compact synths:
- - [J6 chord synth](https://static.roland.com/assets/media/pdf/J-6_eng02_W.pdf) (_[mirror](/pdf/rolan_j6_owners_manual_english.pdf)_)
- - [T8 beat machine](https://static.roland.com/assets/media/pdf/T-8_eng01_W.pdf) (_[mirror](/pdf/rolan_t8_owners_manual_english.pdf)_)
+- Amp [Laney LA35C acoustic](https://www.zikinf.com/manuels/laney-la35c-manuel-utilisateur-en-28749.pdf) (_[mirror](/pdf/laney-la35c.pdf)_)
+- Amp [Marshall Valvestate 8040 (and similar 8xxx series)](https://manualzz.com/download/8600586) (_[mirror](/pdf/marshall-valvestate.pdf)_)
+- Guitar Fender Telecaster American Pro II
+ - [User manual](https://www.fmicassets.com/Damroot/Original/10001/Fender_ElectricGuitars_Manual.pdf) (_[mirror](/pdf/Fender_ElectricGuitars_Manual.pdf)_)
+ - [Service manual](https://www.fmicassets.com/Damroot/Original/10001/SM_011394XXXX_Am_Pro_II_Telecaster.pdf) (_[mirror](/pdf/SM_011394XXXX_Am_Pro_II_Telecaster.pdf)_)
+- [Lottie Canto - Colour Palette](/pdf/lottie_canto_colour_palette.pdf)
+- Midi Controller [Akai MPK mini mk3](https://cdn.inmusicbrands.com/akai/mpk3mini/MPK-mini-Quickstart-Guide-v1_3.pdf) (_[mirror](/pdf/Akai_mpk_mini_mk3_quickstart_guide_v1_3.pdf)_)
+- Roland Aira Compact synths:
+ - [J6 chord synth](https://static.roland.com/assets/media/pdf/J-6_eng02_W.pdf) (_[mirror](/pdf/rolan_j6_owners_manual_english.pdf)_)
+ - [T8 beat machine](https://static.roland.com/assets/media/pdf/T-8_eng01_W.pdf) (_[mirror](/pdf/rolan_t8_owners_manual_english.pdf)_)
### Misc
-- [Boss Guitar Effects Guide Book Vol.20](https://cdn.roland.com/assets/media/pdf/guitar_effects_guidebook_vol_20.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_guitar_effects_guidebook_vol_20.pdf)_)
-- [The science of electric guitars and guitar electronics](https://guitarscience.net/papers/guibook.pdf) (_[mirror](/pdf/the_science_of_electric_guitars_and_guitar_electronic.pdf)_)
-- [Advanced DIY effect pedals](https://guitar-gear.ru/forum/index.php?app=core&module=attach§ion=attach&attach_id=39391&usg=AOvVaw2IgS-cfBeiFW7RWgrPUhWA) (_[mirror](/pdf/advanced_diy_effect_pedals.pdf)_)
+- [Boss Guitar Effects Guide Book Vol.20](https://cdn.roland.com/assets/media/pdf/guitar_effects_guidebook_vol_20.pdf) (_[mirror](/pdf/pedal_user_manuals/boss_guitar_effects_guidebook_vol_20.pdf)_)
+- [The science of electric guitars and guitar electronics](https://guitarscience.net/papers/guibook.pdf) (_[mirror](/pdf/the_science_of_electric_guitars_and_guitar_electronic.pdf)_)
+- [Advanced DIY effect pedals](https://guitar-gear.ru/forum/index.php?app=core&module=attach§ion=attach&attach_id=39391&usg=AOvVaw2IgS-cfBeiFW7RWgrPUhWA) (_[mirror](/pdf/advanced_diy_effect_pedals.pdf)_)
_These manuals are not my creation. They are not distributed under the same licence as the rest of this blog. They includes logos, images and trademarks which belong to their respective owners. I have found these manuals distributed by a lot of different sources on the internet so I assume it is fine to have a mirror here, especially because I link to the official resources too._