This commit is contained in:
Alexis Métaireau 2024-04-23 23:05:38 +02:00
parent b23d7a2766
commit a1a22fb57e
No known key found for this signature in database
GPG key ID: 1C21B876828E5FF2
10 changed files with 729 additions and 73 deletions

View file

@ -0,0 +1,28 @@
---
title: Emotional Abuse
author: Marti Tamm Loring
status: draft
---
> Regardless of the terminology [...] this type of violence dismembers the victim's self by systematically attacking her personality, style of communication, accomplishment, values and dreams.
> Rather, the abuser perceives the victim in terms of his own needs and wishes, while the victim struggles to connect with him in a mutually validating and empathic manner. When her efforts are repeatedly met with scornful refusals and other forms of emotional abuse, the victim becomes traumatized and clings ever more desperately to the abuser.
> the interview with the emotionally abused group provided numerous examples of covert communication abuse — discounts, negation, projection, denial, negative labeling, and abandonment Each woman in this group reported that **her husband habitually implied that her feelings and ideas were inadequate and insignificant**. This insidious violence clearly had a powerful negative effect on these women's lives. Its subtle destructiveness was harder to bear than overt threats and criticisms.
## Attachment
> Disruption of connection is the core of emotional abuse, while the dstruggle to attach is the hallmark of the emotionally abused woman. **The typical abuser moves in and out of bonding with the victim**, periodically sharing warmth and empathy, then cutting them off with overt and covert abuse. Confused by the intermittent connection and struggling to regain it, the victim clings anxiously to the abuser. **Her harsh self-blame echoes the abuser's demeaning comments and becomes and internalized shaming mechanism, diminishing self-esteem and eroding the sense of self**.
---
> A victim of emotional abuse usually continues to seek attachment with an abuser who has withdrawn his affection. Hoping to regain the lost warmth, she may cling to him tenaciously. **Attachment, in this specialized sense, is therefore different from *connection***, a relationship characterized by each partner's efforts to empathize with a respond to the other.
---
> When couples tend to accommodate to each other's style of attachment, the more verbal partner will make a conscious effort to cut back on problem-solving discussions, while the less verbal person will strive to open up more often.
>
> In emotional abuse, there is no such respect or attempt to compromise. Instead, the abuser ridicules and demeans the victim's style of attachment and other unique forms of relating. His behavioral repertoire is limited and is driven by his fear of loss and need to control. He displays little care and consideration for his partner or her feelings, and he ignores one of the essential components of the caring process — increase knowledge and understanding of the other person in order to find better ways of responding to him or her.

View file

@ -0,0 +1,136 @@
---
tags: umap, datasette, opendata
---
# Mapping the concentration of not-for-profit organizations
Following a discussion with a friend, I realized the number of not-for-profit
organizations could be a good indicator of activities in a city, potentially
corellating it to well-being.
I wanted to create a [choropleth](https://en.wikipedia.org/wiki/Choropleth_map) map,
so that different cities appear in different colors on the map,
depending on their respective number of organisations.
## Getting the data
The first thing to do was to retrieve the data. I needed two distincts datasets:
- the cities and their shapes, to display them.
- the number of organisations per city.
The first one was easy, thanks to [France GeoJSON](https://france-geojson.gregoiredavid.fr/), I was able to download [the geometries of the cities of my department](https://france-geojson.gregoiredavid.fr/repo/departements/35-ille-et-vilaine/communes-35-ille-et-vilaine.geojson).
For the number of organisations, I found some [data on data.gouv.fr](https://www.data.gouv.fr/fr/datasets/repertoire-national-des-associations/?reuses_page=3#/community-resources), but the comments made me explore [the official journal dataset](https://journal-officiel-datadila.opendatasoft.com/explore/dataset/jo_associations/table/?sort=dateparution).
Turns out it's possible to issue requests on an API, without having to download everything, so I went with this pseudo SQL statement:
```SQL
SELECT count(*) as nb_asso
WHERE departement_libelle=="Ille-et-Vilaine"
GROUP BY "codepostal_actuel"
ORDER BY -nb_asso
```
Which translates [to this URL](https://journal-officiel-datadila.opendatasoft.com/api/explore/v2.1/catalog/datasets/jo_associations/records?select=count(*)%20as%20nb_asso&where=departement_libelle%3D%22Ille-et-Vilaine%22&group_by=codepostal_actuel&order_by=-nb_asso&offset=0)
## Merging the data with jq
I had all the interesting bits, but in two unrelated `json` files.
[jq](https://jqlang.github.io/jq/manual/), a tool to manipulate JSON data allowed me
to merge these files together, using the `--slurpfile` argument:
```bash
jq --slurpfile orgs organizations.json '.features |= map(
.properties |= (. as $props |
($orgs[0].results[] | select(.codepostal_actuel == $props.code) | . + $props)
)
)' cities.geojson > enriched-cities.geojson
```
I still find it a bit hard to read, but basically what this does is:
- use the `cities.geojson` file as an input
- references `organizations.json` as a second input, naming it `orgs`.
- for each of the geojson properties, merge them with the data coming from orgs, matching on the postal code.
It's using `map()` and the `|=` syntax from jq to do this.
So, it works, and produces an enhanced version of the `.geojson`.
But it turns out that the data I got wasn't good enough.
## Second take
It turns out this simple version is returning no results for the biggest city around (Rennes). There is something fishy.
Let's see the kind of data that's inside this `.geojson` file in more details:
```bash
jq '.features[].properties | select(.nom == "Rennes")' cities.geojson
{
"code": "35238",
"nom": "Rennes"
}```
It turns out this code is not the postal code, but the INSEE code, and these aren't used in the other dataset:
```bash
jq '.results[] | select(.codepostal_actuel == "35238")' organizations.json
# Returns nothing
```
The other dataset I had access to is exposing these codes, so I downloaded all the files, imported them in [datasette](https://datasette.io) and issued an SQL query on it:
```SQL
SELECT COUNT(*) AS count, adrs_codeinsee, libcom
FROM base_rna
WHERE adrs_codepostal LIKE '35%'
GROUP BY adrs_codepostal, libcom;
```
The produced data looked like a typical datasette JSON result:
```javascript
{
// …
"rows": [
[
2746,
"35238",
"RENNES"
],
[
14,
"35116",
"FRESNAIS"
],
// other records here…
],
// …
}
```
Here is the updated jq query, defaulting to 0 for the org count when nothing
is found:
```bash
jq --slurpfile orgs organizations.json '
.features |= map(
.properties |= (
. as $props |
((($orgs[0].rows[] | select(.[1] == $props.code))[0]) // 0) as $orgCount |
. + { "orgCount": $orgCount }
)
)
' cities.geojson > enriched-cities.geojson
```
## Visualisation
I've imported this as a choropleth layer in uMap, it looks like this:
<iframe width="100%" height="300px" frameborder="0" allowfullscreen allow="geolocation" src="//umap.openstreetmap.fr/fr/map/concentration-des-associations-en-ille-et-vilaine_1053526?scaleControl=false&miniMap=false&scrollWheelZoom=false&zoomControl=true&editMode=disabled&moreControl=true&searchControl=null&tilelayersControl=null&embedControl=null&datalayersControl=true&onLoadPanel=none&captionBar=false&captionMenus=true"></iframe><p><a href="//umap.openstreetmap.fr/fr/map/concentration-des-associations-en-ille-et-vilaine_1053526?scaleControl=false&miniMap=false&scrollWheelZoom=true&zoomControl=true&editMode=disabled&moreControl=true&searchControl=null&tilelayersControl=null&embedControl=null&datalayersControl=true&onLoadPanel=none&captionBar=false&captionMenus=true">Voir en plein écran</a></p>

View file

@ -0,0 +1,260 @@
---
title: A GeoJSON distributed Key/Value store
status: draft
---
Our requirements for uMap made it clear we don't really need
a complex CRDT library. We need a way to have peers agree on who is the last
writer, or to state it differently, to order the operations.
The rest of the picture is rather simple: just replace the value at a given location.
## The context
In our case, we have a server, and for the foreseable future we will continue to
have one. We don't want to rely on the server to assign timestamps on each write
operation because that would add too much delay, but we can use it to make sure
the messages are transmitted to the right peers.
So:
- The server has a GeoJSON document, and want to sync it with other peers.
- The server has a way to reach all the peers, using a WebSocket connection.
- Peers can go online and offline, and sync their changes with other peers when
they have connection.
## A Hybrid Logical Clock (HLC)
The different peers will send the server operations when something is changed on
their end. We need to have a way for peers to agree on the ordering of the
operations, without having to concert with each other.
One way to solve this is by using an hybrid logical clock. On each peer, an
hybrid physical+ logical clock is kept, composed of:
- The **physical time**: the current clock time.
- A **logical counter**: an incrementing counter, to differentiate between events that happened at the same clock tick.
- A **peer identifier**: A unique identifier for the peer
This makes it possible to order between different "times": first compare
physical times, then logical times, and finally any additional disambiguating
information such as peer identifiers if the other components are equal.
```python
def hlc_compare(hlc1, hlc2):
physical_time1, logical_time1, peer_id1 = hlc1
physical_time2, logical_time2, peer_id2 = hlc2
if physical_time1 != physical_time2:
return (physical_time1 > physical_time2) - (physical_time1 < physical_time2)
elif logical_time1 != logical_time2:
return (logical_time1 > logical_time2) - (logical_time1 < logical_time2)
else:
return (peer_id1 > peer_id2) - (peer_id1 < peer_id2)
```
## Operations
For now, let's reprensent the operations like this:
```python
# Set foobar to peerA
(1712938520, 500, "Peer A", "foobar=peerA")
```
Peers will send operations to the server, which will assign an incremental ID to each, so it's possible to keep track of which operations have been already received by the peers.
| ID | Clock | Payload |
| -- | ----- | ------- |
| 90 | 1712938501, 500, "Peer A" | title=super |
| 99 | 1712938520, 501, "Peer A" | layertype=cluster |
| 100 | 1712938502, 300, "Peer B" | color=blue |
| 101 | 1712938510, 301, "Peer B" | markertype=drop |
| 102 | 1712938520, 502, "Peer A" | foobar=peerA |
| 103 | 1712938510, 302, "Peer B" | foobar=peerB |
As we can see, incremental IDs might not match the clock order.
They are mainly here as a way for the server to know which operations should be
returned to the peers, based on their last known ID.
For instance, if peer A knows up to id 99, when it gets back online it can ask the
server for operations that happened since then, and then apply them locally
before rendering its interface.
## Compacting the data
We need to distinguish between these use cases:
- A new peer enters, and needs to get the freshest view from the server
- An existing peer reconnects, it might have local data to send, and need to reconciliate it with the freshest state.
### A new peer enters
When a new peer enters and needs to get fresh data, we can do it in multiple
ways. The simplest one is to make it redo the exact same things that happened on
other peers: get the same GeoJSON and apply the same operations on it.
It will work, but will require the server to serve all the operations that
happened over time to all clients, which is suboptimal. We can avoid this by
compacting the data on the server prior to serving it.
This view of the document needs to have an HLC associated with each key.
### An existing peer reconnects
```
T0 = Peer A retrieves data. It goes offline with it.
T1 = Peer A updates the data locally
T100 = Peer B updates the data and syncs
T101 = Peer A goes back online.
```
At T101, Peer A will tell the server: "hey, let me know what data you have since T0".
The server will return the operations since then, and Peer A will apply it locally.
It will then send the missing data that happened at T1.
Because peers know the time at which each change has been made, receiving old
data will be applied only if it's fresher than the current one.
## The data
Because we're using GeoJSON, the data is well defined. It looks like this:
```json
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [125.6, 10.1]
},
"properties": {
"name": "Dinagat Islands"
}
}
```
On uMap, a simple `.geojson` map looks like this (it's long, but I already removed a lot of data in there)
```json
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-1.426849365234375,
48.182112019648514
]
},
"properties": {
"name": "Title",
"zoom": 10,
"miniMap": false,
"overlay": {},
"slideshow": {},
"tilelayer": {
"tms": false,
"name": "OSM Positron (Carto)",
"maxZoom": 20,
"minZoom": 0,
"attribution": "Map tiles by [[http://cartodb.com/attributions#basemaps|CartoDB]], under [[https://creativecommons.org/licenses/by/3.0/|CC BY 3.0]]. map data © [[http://osm.org/copyright|OpenStreetMap contributors]] under ODbL ",
"url_template": "https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png"
},
"longCredit": "https://www.data.gouv.fr/fr/datasets/repertoire-national-des-associations/",
"defaultView": "data",
"description": "",
"limitBounds": {},
"onLoadPanel": "caption",
// redacted. Tons of properties
"permissions": {
"edit_status": 3,
"share_status": 1,
"owner": {
"id": 2712,
"name": "ametaireau",
"url": "/fr/user/ametaireau/"
},
"editors": []
},
"umap_id": 1053526,
"umap_version": "2.1.3",
"featuresHaveOwner": false,
"datalayers": [
{
"id": "badb1518-9ff1-40a2-b8a8-4d6976904469",
"fill": true,
"name": "Concentration d'associations",
"type": "Choropleth",
"opacity": 0.1,
"editMode": "disabled",
"labelKey": "{nom}: {orgCount} ",
"browsable": true,
"inCaption": true,
"showLabel": null,
"choropleth": {
"mode": "kmeans",
"breaks": "0,11,25,51,149,420,708,2746,2746",
"classes": 8,
"property": "orgCount"
},
"remoteData": {},
"description": "Le nombre d'associations par commune",
"fillOpacity": 0.8,
"permissions": {
"edit_status": 0
},
"displayOnLoad": true,
"labelInteractive": false
}
]
}
}
```
And a layer looks like this:
```json
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [125.6, 10.1]
},
"properties": {
"nom": "Dinagat Islands",
"orgCount": 10,
}
}
],
"_umap_options": {
"displayOnLoad": true,
"inCaption": true,
"browsable": true,
"editMode": "advanced",
"name": "Photographies de 2019",
"color": "Crimson",
"iconUrl": "/uploads/pictogram/embassy-24.png",
"iconClass": "Ball",
"remoteData": {},
"description": ""
}
}
```
It's interesting to note that the data here has mixed purpose. It's at the same
time useful data for uMap, and for the geographical objects.
Now, what we want to do is to propagate the changes from one peer to another,
going trough the server.
Because uMap doesn't internally use the `GeoJSON` keys to handle its changes, we
will need to match between changes in the geoJSON and changes in uMap. It
actually goes both ways, when detecting the modified data, and when applying the
received changes.

View file

@ -0,0 +1,34 @@
Il y avait celui qu'on avait fini par nommer « gris ». Il n'avait pas toujours été comme ça, mais ces dernières années, c'est comme si il s'était perdu dans les méandres de ce qui avaient étés, il y a longtemps, ses envies. Voyager, c'était à l'époque pour lui un appel, comme une envie d'ailleurs, toujours présente alors même qu'on y est déjà, ailleurs.
Lui qui croyait aux rencontres, elles ne lui suffisaient plus. Un trajet en chassait un autre, alors que le premier n'était pas terminé. Le voyage lui avait laissé des valises sous les yeux, peut-être a force de soulever et de reposer celles qu'il se trainait un peu partout avec lui.
Il avait d'ailleurs fini par les remplacer, ses grosses valises par une petite mallette, dans laquelle il pouvait ranger tout ce qui était important pour lui: ses livres, sa montre à ressors, son calepin a la couverture bleue déchirée, et surtout, bien sur, son rasoir manuel, avec lequel il aimait tant s'amuser, de manière un peu dérangeante. Il l'avait même utilisé une fois pour faire peur à des enfants un peu trop bavards avec qui il partageait la cabine.
---
Assise en bord de rivière, Réga regardait les libellules jouer les unes avec les autres, s'envoler puis se reposer, sans trop comprendre ce qu'elles faisaient, mais ça ne semblait pas la déranger, ni même la questionner. Ce qui était n'était pas là pour être questionné.
Elle avait une quiétude rassurante au fond des yeux, verts et bleus, selon la luminosité, comme si chez elle la peine ne pouvait pas exister, comme si elle avait trouvé le remède au froid, à l'éloignement. Elle était profonde, pleine, joyeuse et ouverte. Parfois, quand la conversation démarrait, sans se faire attendre, c'était pour y trouver des échos, comme quand plusieurs cerveaux se mêlaient pour sortir des accords, des harmoniques, qui se répondaient de manière quasiment évidente. Elle ne parlait pas, elle chantait. La conversation était musicale ou n'était pas.
---
Il y avait aussi Lanterne, nommée comme ça pour les nombreuses embuches desquelles elle nous avait sorti. C'était un phare dans la noirceur troublante de ce qui avait été notre vie par moments. Une énergie brute, une clairvoyance parfois désobligeante. On ne l'aimait pas vraiment, elle nous énervait un peu mais on était bien content de la trouver en cas de besoin. Elle était toujours là, dans ces moments là. Dans la tempête, on pouvait compter sur elle, par jour de beau temps, elle se faisait oublier, comme si sa raison d'être était uniquement les autres
---
A la regarder, elle étant ronde, luisante, lisse et belle. Mais elle pouvait aussi être percutante et sonore quand il le fallait. Ce que certains pouvaient appeler « un personnage ». C'était un personnage, sonnette.
On pouvait la trouver posée sur le bord d'un comptoir ou à l'entrée d'une maison.
Parfois en mouvement sur une bicyclette.
---
Contraintes:
- Chacun·e a choisi un objet, et des personnages sont créés à partir de ces objets: une mallette, un harmonica, une lampe tempête, et une sonnette.

View file

@ -5,8 +5,42 @@ template: worklog
total_days: 90
---
## Vendredi 20 Avril 2024 (6h, 4/5)
J'ai repris le travail que j'avais entammé en tant que « preuve de concept » pour l'intégrer dans une version plus mure. J'ai passé du temps à définir les étapes nécessaires pour arriver à avoir de la synchronisation temps réel, et j'ai déroulé. Je synchronise les propriétés des cartes, ainsi que les features (en tout cas les marqueurs).
Je ne suis pas encore certain que ce soit utile de vérifier le format des messages sur le serveur, et j'ai envie de simplifier plusieurs bouts de code / d'architecture, par exemple ce sont les composants qui se déclarent « synchronisables » et je pense que ça pourrait être fait de manière plus explicite.
## Jeudi 19 Avril 2024 (4h, 4/5)
En écrivant les notes, je me rends compte que la raison pour laquelle les websockets ne sont pas same-origin avec notre domaine n'est pas que ça pourrait être hebergé sur un autre domaine, mais que wss:// et https:// ne semblent pas être considérés comme le même domaine. D'où [la pirouette nécessaire](https://websockets.readthedocs.io/en/stable/topics/authentication.html#cookie) (à base d'iframes) pour lier le cookie au bon domaine.
Je me dis qu'une des options est que le serveur nous renvoie un token signé par le serveur, qui pourrait contenir les permissions qui sont données, dans le même esprit que des JWT.
Je tombe sur une partie du code qui utilise du SHA1 pour les signatures, que je considérais comme insécure. En [creusant un peu](https://crypto.stackexchange.com/questions/845/what-is-wrong-with-using-sha1-in-digital-signatures-why-is-a-robust-hash-functi), je me rends compte que pour le moment, sha1 est considéré insécure, mais qu'il n'y a pas encore d'attaques connues dessus qui permettent d'utiliser du « second-pre-image », c'est à dire des signatures différentes de celles d'origine, mais qui sont aussi valides. On est bon pour ce coup là.
## Mardi 17 Avril 2024 (6h, 3/5)
J'avance sur un première implementation du serveur de websockets, avec l'idée de relayer les messages entre les clients. J'attaque par l'authentification des connections, qui est nécessaire pour éviter que des attaquants (potentiels) utilisent la connection websocket pour faire par exemple de l'élévation de privilèges (pour pouvoir éditer un layer auquel iels n'ont normalement pas accès).
Je passe du temps à lire les différents moyens de s'authentifier, et je commence une implémentation. J'en profite pour valider les entrées avec Pydantic.
## Lundi 16 Avril 2024 (7h, 4/5)
Une matinée passée à travailler sur de l'UX, en completant le document donné par Aurélie. Ça donne quelques idées c'est chouette.
L'après midi, je me synchronise avec David, puis avec Yohan. Je merge la PR pour pouvoir faire du rendu « dynamique » (ce qui va permettre de faire du rendu depuis des évènements distants).
## Vendredi 12 Avril 2024 (6h, 5/5)
Je continue ma compréhension de ce qu'on pourrait techniquement faire pour supporter du hors-ligne. J'ai rédigé un bout de README pour un projet qui pourrait faire une sorte de K/V store pour des documents GeoJSON. Tout n'est pas encore clair, mais ça progresse.
## Lundi 08 Avril 2024 (5h, 4/5)
Une après-midi à Grenoble avec Aurélie, on a passé du temps à creuser les aspects UX sur la collaboration temps réel, en faisant un persona et en prenant un cas concret d'utilisation.
Une réunion sur la documentation avec David, Aurélie, Framasoft et Antoine Riche. C'était chouette de pouvoir discuter clairement de leurs intentions sur le sujet. Ça me donne envie d'avancer, content que David prenne le sujet, on va surement partir sur notre propre documentation.
J'ai passé du temps à lire la documentation sur les WebSockets en python, je comprends mieux comment faire du routing, et comment tout ça va passer à l'échelle.
## Vendredi 05 Avril 2024 (4h, 4/5)

View file

@ -19,6 +19,7 @@ projects: umap
- Apprendre avec d'autres personnes. C'était grisant d'échanger autour du code, de comprendre des concepts en faisant.
- Relâcher la pression pour avancer sur uMap, ça fait du bien de travailler quand je sens que ça va avancer, et de ne pas le faire quand je sens que j'ai la tête ailleurs.
## Des peines 😬
- J'étais complètement décalé et en gros manque de sommeil. J'aimerai m'en rendre compte plus tôt pour changer de schéma.

38
content/weeknotes/24.md Executable file
View file

@ -0,0 +1,38 @@
---
date: 2024-04-11
headline: notes hebdo de la semaine
projects: umap
---
# Notes hebdo #24
## Ce qui s'est passé
**🗺️ [uMap](https://umap-projet.org)**
: Deux demi journées de travail
: Une discussion avec Vadims (l'auteur de JSON Joy) autour des enjeux à utiliser des CRDTs dans uMap. Une approche où on implémente nous même un CRDT simple côté client et serveur commence à ce dessiner, pour que le serveur soit capable de retourner un fichier geoJSON si besoin.
: Des changements dans la suite de tests, c'est bon, c'est intégré. J'en ai profité pour repasser un coup sur les changements en attente pour les rendre compatibles, et j'ai trouvé des bugs avant qu'ils soient en prod. Youpi !
: Des dépots de demande de financement pour la suite des évènements. La proposition pour ajouter le support des tuiles vectorielles dans uMap est déposée.
🚨**[Argos](https://framasoft.frama.io/framaspace/argos/)**
: On se prépare à publier la première version, j'ai refait une passe sur la documentation, et fait un peu de revue de code.
**Divers**
: J'ai participé a un forum ouvert à Rennes.
: J'ai refait mon CV et répondu à un appel d'offre qui pourrait être intéressant. Je n'en sais pas plus pour l'instant !
## Des joies 🤗
- Aménager des temps de discussion quand j'en avais besoin. C'est confortable de pouvoir adapter mon emploi du temps en fonction.
- Discuter d'aspects techniques avec des personnes extérieures et qui se rendent disponibles. C'est vraiment enthousiasment.
- Discuter de l'importance des compétences psychosociales dans un évènement d'abord à vocation technique.
## Des peines 😬
- La semaine était trop dense (entre les activités du soir, les aspects logistiques et les transports de fin de semaine) ce qui fait que j'étais vraiment fatigué en fin de semaine. J'aimerais mieux m'écouter quand je le vois venir, et m'aménager des temps de respiration.
- Je me suis senti mal à l'aise durant certaines discussions dans un forum ouvert. Je mesure en creux l'importance de l'accueil et l'attention a ce que la parole circule lors de précédents forums ouverts auxquels j'ai pu participer. J'aimerai mieux comprendre ma frustration quand elle arrive et m'autoriser à faire autre chose, à fortiori lors d'un forum ouvert (qui est l'endroit parfait pour s'écouter).
- J'ai passé du temps sur des sujets périphériques pour uMap (réunion, demandes de financement), ce qui fait que j'ai du mal à avancer concrètement sur la synchro. J'ai envie de protéger un peu plus de mon temps pour me sentir plus efficace.
## Vu, Lu, etc
- 🎤 Vu Clara Ysé en concert. C'était très bien, même si j'étais malheureusement trop fatigué pour vraiment en profiter.
- 🎧 Découvert [Zéro Virgule](https://audioblog.arteradio.com/blog/223731/zero-virgule) une série de podcasts sur le travail (merci Zero Janvier). Je suis en cours d'écoute.

64
content/weeknotes/25.md Normal file
View file

@ -0,0 +1,64 @@
---
date: 2024-04-15
headline: notes hebdo de la semaine
projects: umap
---
# Notes hebdo #25
Entre Grenoble, Crest et Rennes. Je récupère de l'energie !
## Ce qui s'est passé
**🗺️ [uMap](https://umap-projet.org)**
: On s'est rencontré avec Aurélie, et c'était l'occasion d'avancer sur la partie design des fonctionalités de collaboration temps-réel. On a commencé à faire des persona et à décrire plus finement les cas d'usage.
: Une discussion pour clarifier vers où on va tendre concernant la documentation utilisateur.
: J'ai passé du temps à lire de la documentation sur comment passer à l'échelle des WebSockets.
🚨**[Argos](https://framasoft.frama.io/framaspace/argos/)**
: Sur le temps long, quelques discussions pour peaufiner la v1.
💶**[Ihatemoney](https://ihatemoney.org)**
: Une discussion sur le futur du projet, qui va passer en « mode maintenance », pour faciliter la vie des contributeurs.
: Une revue de pas mal de contributions en attente, pour faire du tri.
**🧺 [La Chariotte](https://chariotte.fr/)**
: Un weekend de travail à Grenoble, l'occasion de rencontrer l'équipe et de faire collectif, petit à petit.
: Se mettre d'accord sur une vision commune
## Des joies 🤗
- Réussir à ne pas me mettre la pression: avancer quand je sens que c'est le bon moment.
- Prendre le temps de lire, d'apprécier le silence, de profiter du soleil. Voir ce que ça me procure en terme de bien-être, et mesurer l'impact sur ma capacité de concentration au travail.
- Expérimenter la prise de décision par consentement.
- Faire de la méditation quand j'en ai senti le besoin. En ressentir les bienfaits immédiats.
## Des peines 😬
- Je n'ai pas tenu les temps que je m'étais donné pour travailler, et j'ai débordé sur d'autres moments. Je ne sais pas encore trop quoi en penser.
## Vu, Lu, etc
- Plein d'articles autour de l'évolution du CSS ces dernières années. Ça me donne envie de refaire le CSS de ce site, je ne sais même pas comment ça tient encore debout !
- [les techniques CSS utilisées chez Campfire](https://dev.37signals.com/modern-css-patterns-and-techniques-in-campfire/)
- [L'utilisation avancée des variables CSS](https://gomakethings.com/an-advanced-way-to-use-css-variables/)
- [Comment utiliser les layers CSS](https://piccalil.li/blog/how-were-approaching-theming-with-modern-css/)
- Vu le documentaire « La trahison de la technologie, portrait de Jacques Ellul » (de 1996, [en partie disponible sur YouTube](https://www.youtube.com/watch?v=01H5-s0bS-I))
- Parcouru « Emotional Abuse » de Marti Tamm Loring. Très fort et utile. (Dommage que je ne puisse pas le continuer pour l'instant).
## Notes
### Reflexes
> La technique nous oblige à aller de plus en plus vite. Et elle va remplacer la reflexion par le réflexe. La réflexion c'est le fait que quand j'ai fait une expérience, je réfléchis sur cette expérience. Le réflexe c'est savoir immédiatement ce qu'il faut faire dans telle ou telle circonstance, sans réflechir. La technique demande qu'on ne réfléchisse pas.
> Il faut avoir des reflexes. Ce qu'on demande dans la technique c'est : ne réfléchissez pas, ayez des reflexes.
>
> — Jacques Ellul (dans le documentaire « La trahison technologique »)
Je trouve ça assez vertigineux de lire ça maintenant, avec l'arrivée massive de l'IA dans les usages et à qui parfois on vient déléguer la réfléxion, justement.
### Abus
> A victim of emotional abuse usually continues to seek attachment with an abuser who has withdrawn his affection. Hoping to regain the lost warmth, she may cling to him tenaciously. **Attachment, in this specialized sense, is therefore different from *connection***, a relationship characterized by each partner's efforts to empathize with a respond to the other.
>
> — Emotional Abuse, Marti Tamm Loring

50
content/weeknotes/26.md Normal file
View file

@ -0,0 +1,50 @@
---
date: 2024-04-23
headline: notes hebdo de la semaine
projects: umap
---
# Notes hebdo #26
## Ce qui s'est passé
**🗺️ [uMap](https://umap-projet.org)**
: Ecriture de parcours utilisateur·ice, grace à un outil qui propose de créer des persona, d'imaginer les tâches, questions, freins, moments positifs et opportunités liées.
: Approfondir ma compréhension technique sur les WebSockets, entre autres sur les questions d'authentification.
: [Commencer à écrire le code](https://github.com/umap-project/umap/pull/1754) qui apporte les fonctionnalités de collaboration temps réel, et clarifié les étapes qui seront nécessaires pour arriver à bon port.
: Continuer mon exploration autour de l'utilisation des horloges logiques hybrides, qui ont des propriétés tout à fait intéressantes pour de la synchronisation.
## Des joies 🤗
- Récolter des idées d'interface et de fonctionnalités en suivant une méthodologie nouvelle. J'aime beaucoup le moment de découverte, et la simplicité avec laquelle l'outil permet de trouver de nouvelles pistes.
- Me baser sur le travail effectué durant ces derniers, et voir peu à peu se matérialiser la fameuse « collaboration temps réel ». C'est satisfaisant de savoir que les modifications apportées ces derniers mois sont utiles.
- Sentir qu'il est possible d'exprimer mon intimidation et que ce soit pris en considération. J'ai apprécié les questions et les échanges qui n'était pas seulement centrés sur la technique lors d'une rencontre avec des enjeux pro.
- Prendre le temps de discuter des enjeux et dynamiques actuelles dans d'autres collectifs de travail. J'aime ces échanges et les relations qui en découlent.
- Déconnecter le temps d'un long weekend à la mer, bien manger, profiter des ballades. Me sentir re-sourcé.
- Voir quand mes limites émotionelles sont en train d'être dépassées, et savoir comment aller me resourcer ailleurs.
## Des peines 😬
- Je me suis senti sur la défensive quand certains de mes choix techniques ont été questionnés (sans que je l'ai sollicité). Ça parle de confiance (en moi, et qui m'est accordée). J'aimerai dépasser ce sentiment d'imposture, et questionner pour mieux comprendre les intentions en face — et peut-être les peurs —, avant d'aller sur la discussion technique.
- J'ai délégué un moment d'apprentissage à un LLM, pour finalement me rendre compte que les réponses formulées par l'outil n'étaient pas correctes. Ça me donne envie de prendre le temps de lire des articles et de les comprendre plutôt que d'essayer de gagner du temps.
- Je me sens impatient durant certains temps de réunion, qui me prennent de l'énergie là ou je voudrais en gagner. J'aimerai m'autoriser à faire autre chose à ces moments là.
## Vu, Lu, etc
- 🎥 Vu [Mars Express](https://youtu.be/VG0bJHwUR0I) durant le festival national du Film d'animation. Je n'avais aucune attente et j'ai été agréablement surpris par l
- ⏯️ Vu [Ceci n'est pas un Atlas / La cartographie comme outil de luttes, 21 exemples à travers le monde / orangotango+ - Éditions du commun](https://www.editionsducommun.org/collections/all/products/ceci-nest-pas-un-atlas-orangotango-nepthys-zwer)
- 🎥 Vu Yannick, de Quentin Dupieux.
- 📘 (re) commencé « La volonté de changer », de bell hooks. Cette fois-ci en Français.
- 📘 (re) lu [« Gestion de(s) conflit(s) » de Rose-Marie Dethier](https://www.cdgai.be/publications/gestion-des-conflits/), reçu au format papier. J'aime beaucoup l'approche synthétique qui y est proposée. Une belle boîte à outils.
---
## Feedback
> The trouble arises when we realize that even our observations are sullied by our perspectives and beliefs. I may notice the basketball because Ive been instructed or incentivized to pay attention to it, or have simply made a choice to do so, even while you are—for probably very good reasons—concerned about the gorilla.
>
> — [What you see](https://everythingchanges.us/blog/what-you-see/)
Intéressant de détecter nos angles morts, ici en terme d'attention. En reprenant l'exemple du gorille qui marche au milieu d'un terrain de basket dans lequel on est concentré à compter les passes.
L'exemple est étiré pour parler de ce à quoi on accorde notre attention, et potentiellement tout ce à coté de quoi on passe, surtout dans les moments ou on propose de donner du feedback à quelqu'un, tout en passant à côté du feedback qu'on pourrait se faire à soi même.

View file

@ -1,74 +1,85 @@
pre { line-height: 125%; margin: 0; }
td.linenos pre { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }
span.linenos { color: #000000; background-color: #f0f0f0; padding: 0 5px 0 5px; }
td.linenos pre.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding: 0 5px 0 5px; }
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight { background: #f8f8f8; }
.highlight .c { color: #408080; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #008000; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
.highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #BC7A00 } /* Comment.Preproc */
.highlight .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
.highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */
.highlight .cs { color: #408080; font-style: italic } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #FF0000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #00A000 } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0044DD } /* Generic.Traceback */
.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008000 } /* Keyword.Pseudo */
.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #B00040 } /* Keyword.Type */
.highlight .m { color: #666666 } /* Literal.Number */
.highlight .s { color: #BA2121 } /* Literal.String */
.highlight .na { color: #7D9029 } /* Name.Attribute */
.highlight .nb { color: #008000 } /* Name.Builtin */
.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.highlight .no { color: #880000 } /* Name.Constant */
.highlight .nd { color: #AA22FF } /* Name.Decorator */
.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0000FF } /* Name.Function */
.highlight .nl { color: #A0A000 } /* Name.Label */
.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #19177C } /* Name.Variable */
.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #666666 } /* Literal.Number.Bin */
.highlight .mf { color: #666666 } /* Literal.Number.Float */
.highlight .mh { color: #666666 } /* Literal.Number.Hex */
.highlight .mi { color: #666666 } /* Literal.Number.Integer */
.highlight .mo { color: #666666 } /* Literal.Number.Oct */
.highlight .sa { color: #BA2121 } /* Literal.String.Affix */
.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
.highlight .sc { color: #BA2121 } /* Literal.String.Char */
.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
.highlight .sx { color: #008000 } /* Literal.String.Other */
.highlight .sr { color: #BB6688 } /* Literal.String.Regex */
.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
.highlight .ss { color: #19177C } /* Literal.String.Symbol */
.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0000FF } /* Name.Function.Magic */
.highlight .vc { color: #19177C } /* Name.Variable.Class */
.highlight .vg { color: #19177C } /* Name.Variable.Global */
.highlight .vi { color: #19177C } /* Name.Variable.Instance */
.highlight .vm { color: #19177C } /* Name.Variable.Magic */
.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */
.highlight { background: #282C34; color: #ABB2BF }
.highlight .c { color: #7F848E } /* Comment */
.highlight .err { color: #ABB2BF } /* Error */
.highlight .esc { color: #ABB2BF } /* Escape */
.highlight .g { color: #ABB2BF } /* Generic */
.highlight .k { color: #C678DD } /* Keyword */
.highlight .l { color: #ABB2BF } /* Literal */
.highlight .n { color: #E06C75 } /* Name */
.highlight .o { color: #56B6C2 } /* Operator */
.highlight .x { color: #ABB2BF } /* Other */
.highlight .p { color: #ABB2BF } /* Punctuation */
.highlight .ch { color: #7F848E } /* Comment.Hashbang */
.highlight .cm { color: #7F848E } /* Comment.Multiline */
.highlight .cp { color: #7F848E } /* Comment.Preproc */
.highlight .cpf { color: #7F848E } /* Comment.PreprocFile */
.highlight .c1 { color: #7F848E } /* Comment.Single */
.highlight .cs { color: #7F848E } /* Comment.Special */
.highlight .gd { color: #ABB2BF } /* Generic.Deleted */
.highlight .ge { color: #ABB2BF } /* Generic.Emph */
.highlight .ges { color: #ABB2BF } /* Generic.EmphStrong */
.highlight .gr { color: #ABB2BF } /* Generic.Error */
.highlight .gh { color: #ABB2BF } /* Generic.Heading */
.highlight .gi { color: #ABB2BF } /* Generic.Inserted */
.highlight .go { color: #ABB2BF } /* Generic.Output */
.highlight .gp { color: #ABB2BF } /* Generic.Prompt */
.highlight .gs { color: #ABB2BF } /* Generic.Strong */
.highlight .gu { color: #ABB2BF } /* Generic.Subheading */
.highlight .gt { color: #ABB2BF } /* Generic.Traceback */
.highlight .kc { color: #E5C07B } /* Keyword.Constant */
.highlight .kd { color: #C678DD } /* Keyword.Declaration */
.highlight .kn { color: #C678DD } /* Keyword.Namespace */
.highlight .kp { color: #C678DD } /* Keyword.Pseudo */
.highlight .kr { color: #C678DD } /* Keyword.Reserved */
.highlight .kt { color: #E5C07B } /* Keyword.Type */
.highlight .ld { color: #ABB2BF } /* Literal.Date */
.highlight .m { color: #D19A66 } /* Literal.Number */
.highlight .s { color: #98C379 } /* Literal.String */
.highlight .na { color: #E06C75 } /* Name.Attribute */
.highlight .nb { color: #E5C07B } /* Name.Builtin */
.highlight .nc { color: #E5C07B } /* Name.Class */
.highlight .no { color: #E06C75 } /* Name.Constant */
.highlight .nd { color: #61AFEF } /* Name.Decorator */
.highlight .ni { color: #E06C75 } /* Name.Entity */
.highlight .ne { color: #E06C75 } /* Name.Exception */
.highlight .nf { color: #61AFEF; font-weight: bold } /* Name.Function */
.highlight .nl { color: #E06C75 } /* Name.Label */
.highlight .nn { color: #E06C75 } /* Name.Namespace */
.highlight .nx { color: #E06C75 } /* Name.Other */
.highlight .py { color: #E06C75 } /* Name.Property */
.highlight .nt { color: #E06C75 } /* Name.Tag */
.highlight .nv { color: #E06C75 } /* Name.Variable */
.highlight .ow { color: #56B6C2 } /* Operator.Word */
.highlight .pm { color: #ABB2BF } /* Punctuation.Marker */
.highlight .w { color: #ABB2BF } /* Text.Whitespace */
.highlight .mb { color: #D19A66 } /* Literal.Number.Bin */
.highlight .mf { color: #D19A66 } /* Literal.Number.Float */
.highlight .mh { color: #D19A66 } /* Literal.Number.Hex */
.highlight .mi { color: #D19A66 } /* Literal.Number.Integer */
.highlight .mo { color: #D19A66 } /* Literal.Number.Oct */
.highlight .sa { color: #98C379 } /* Literal.String.Affix */
.highlight .sb { color: #98C379 } /* Literal.String.Backtick */
.highlight .sc { color: #98C379 } /* Literal.String.Char */
.highlight .dl { color: #98C379 } /* Literal.String.Delimiter */
.highlight .sd { color: #98C379 } /* Literal.String.Doc */
.highlight .s2 { color: #98C379 } /* Literal.String.Double */
.highlight .se { color: #98C379 } /* Literal.String.Escape */
.highlight .sh { color: #98C379 } /* Literal.String.Heredoc */
.highlight .si { color: #98C379 } /* Literal.String.Interpol */
.highlight .sx { color: #98C379 } /* Literal.String.Other */
.highlight .sr { color: #98C379 } /* Literal.String.Regex */
.highlight .s1 { color: #98C379 } /* Literal.String.Single */
.highlight .ss { color: #98C379 } /* Literal.String.Symbol */
.highlight .bp { color: #E5C07B } /* Name.Builtin.Pseudo */
.highlight .fm { color: #56B6C2; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #E06C75 } /* Name.Variable.Class */
.highlight .vg { color: #E06C75 } /* Name.Variable.Global */
.highlight .vi { color: #E06C75 } /* Name.Variable.Instance */
.highlight .vm { color: #E06C75 } /* Name.Variable.Magic */
.highlight .il { color: #D19A66 } /* Literal.Number.Integer.Long */