Compare commits
26 Commits
2e5bf7d1a7
...
master
Author | SHA1 | Date | |
---|---|---|---|
6ea54b1218
|
|||
2fa462c0ee
|
|||
9dfa0e63bb
|
|||
6e78335f5d
|
|||
aa8990e1c7
|
|||
719e4b2780
|
|||
9feeed82e5
|
|||
d410b35b37
|
|||
e8c7b3d1e7
|
|||
1513d0cc9a
|
|||
df0ef69452
|
|||
324da3208b
|
|||
5d223655fc
|
|||
18ea6afb94
|
|||
16705027d6 | |||
2a29096d17 | |||
50825985b7 | |||
ab9ee4660a | |||
4e9442c835 | |||
015b896f65 | |||
e552583393 | |||
04eda32fa3 | |||
5e977d44a4 | |||
47ed93bf21 | |||
a282d484a3 | |||
c330a3991d |
@@ -1,14 +1,48 @@
|
||||
:PROPERTIES:
|
||||
:ID: ca50d517-3e8a-4d03-ba38-7ff411e87408
|
||||
:mtime: 20220130102557
|
||||
:mtime: 20220928120750
|
||||
:ctime: 20211230101331
|
||||
:END:
|
||||
#+title: Software
|
||||
|
||||
* Conceptes
|
||||
** /LBYL/ et /EAFP/
|
||||
*** *L*ook *B*efore *Y*ou *L*eap
|
||||
Technique consistant à anticiper les éventuelles erreurs (en vérifiant un pointeur /null/ par exemple).
|
||||
*** *E*asier to *A*sk *F*orgiveness than *P*ermission
|
||||
Technique privilégiant l'interception d'erreurs à leur anticipation. Cela permet :
|
||||
* De réduire la charge CPU en vérifications, surtout lorsque la probabilité d'exception est faible, d'autant plus à
|
||||
partir de Python3.11 ([[https://github.com/python/cpython/issues/84403][zero-cost exceptions]]).
|
||||
Il est nécessaire que le language mis en oeuvre permette l'interception d'erreurs (pas le cas du C ou du Go).
|
||||
|
||||
* Design pattern
|
||||
TODO
|
||||
|
||||
* Classement/tri de données
|
||||
** [[id:6af01039-a0a9-46fc-abe8-82f9662bc4b7][heap sort algorithm]]
|
||||
|
||||
* Langages
|
||||
** Compilés
|
||||
*** [[id:ed8be72a-8a4d-4ef7-92e4-78d07095deaf][C++]]
|
||||
*** [[id:673d43c9-0b31-4f28-b550-4eb615c41dac][Rust]]
|
||||
** Interprétés
|
||||
*** [[id:a877b82e-4925-41de-8903-8109dd98e773][Bash]]
|
||||
*** [[id:33ef1e68-70ad-43c8-850d-4b8ed2c5ea16][Elisp]]
|
||||
*** [[id:d4197090-4ee5-4fa3-ba2d-a70ce9953923][Javascript]]
|
||||
*** [[id:4fabfe6a-b104-464f-8a87-dfd7d761dbcc][Python]]
|
||||
* Design pattern
|
||||
|
||||
* Composition de docs
|
||||
** [[id:3250943b-32f0-4bdc-b0d2-5fbcf1724f36][Latex]]
|
||||
|
||||
* Méthodes/Principes
|
||||
** [[id:b827c6e7-fe86-4301-a72c-dfaee85e142f][SOLID]]
|
||||
** [[id:6da0b985-e6f4-4454-bb6a-e941b722365b][Test driven development]]
|
||||
|
||||
* Gestionnaire de configuration
|
||||
** [[id:e93719b3-088d-4fe7-9ef8-fc9a4fd84827][Git]]
|
||||
|
||||
* Outils
|
||||
** Diff
|
||||
*** [[id:67317dba-3771-405f-ae58-0ef13062975d][diffsitter]]
|
||||
** Performances
|
||||
*** [[https://www.intel.com/content/www/us/en/developer/tools/oneapi/vtune-profiler.html#gs.26xa9e][Intel® VTune™ Profiler]]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
:PROPERTIES:
|
||||
:ID: 4fabfe6a-b104-464f-8a87-dfd7d761dbcc
|
||||
:mtime: 20220130162518
|
||||
:mtime: 20221003215204
|
||||
:ctime: 20211230101535
|
||||
:END:
|
||||
#+title: Python
|
||||
@@ -9,29 +9,233 @@
|
||||
* Language
|
||||
** Classe
|
||||
*** Méthodes dunder (Double UNDERscore method)
|
||||
* [[id:dc2a8693-7158-4155-8eff-fc35a21a077d][La méthode dunder __missing__]]
|
||||
**** [[id:5803422c-c089-4369-93cc-80caca71a26b][La méthode __bool__]]
|
||||
**** [[id:aaf77222-82d2-492c-bf5f-2dd47659b1be][La méthode __new__]]
|
||||
**** [[id:dc2a8693-7158-4155-8eff-fc35a21a077d][La méthode __missing__]]
|
||||
**** [[id:0d9a7351-babd-4394-9d95-1d40cb46f615][La méthode __prepare__]]
|
||||
**** [[id:d1877b3b-3fe5-43d5-9be2-afb5ffe6b918][La méthode __hash__]]
|
||||
**** Les méthodes __repr__ et __str__
|
||||
La méthode ~__repr__~ est utilisée pour le debug quand ~__str__~ pour l'utilisateur (/good looking strings/).
|
||||
*** [[id:1512a18b-221a-4f15-90a0-9ccac023dfd6][Method Resolution Order]]
|
||||
** Types
|
||||
*** [[id:f892dbdd-0cb5-4204-bca0-09aafb41f7ca][Dataclasses]]
|
||||
*** [[id:67410dad-d959-4029-b281-9bf1c9e69ede][Generator]]
|
||||
*** [[id:234f4590-b484-4286-9dbd-49612f4657be][NamedTuple]]
|
||||
*** [[id:cc0e3fd0-2832-4bf6-909f-354507f7ed11][Set et frozenset]]
|
||||
*** [[id:8b686fdd-2abd-459d-8d8d-0c57915de8fb][String]]
|
||||
*** [[id:ed7551e9-706c-4bc3-90fb-e5a63a4a7903][Table de hashage]]
|
||||
** Fonctions Built-in
|
||||
*** [[id:487f57f5-e9fc-4df7-ae14-b41f9c1fa186][Fonction vars]]
|
||||
*** [[id:acda43fa-70be-4939-9128-47114e48e4cb][Fonction zip]]
|
||||
** Functools module
|
||||
*** [[id:25d994fd-375b-429d-af38-6afba818159f][functools.singledispatch]]
|
||||
|
||||
|
||||
* Frameworks
|
||||
** Web
|
||||
*** [[id:26b04294-75e8-4043-a9a6-a20acd952963][Flask]]
|
||||
|
||||
|
||||
* UI
|
||||
** GUI
|
||||
*** [[https://kivy.org/#home][Kiwi]]
|
||||
*** [[https://www.libavg.de/site/projects/libavg/wiki/FeatureList][libAvg]]
|
||||
*** [[https://pysimplegui.readthedocs.io/en/latest/][PySimpleGui]]
|
||||
*** [[https://pyforms.readthedocs.io/en/latest/][Pyforms]]
|
||||
Framework permettant d'exécuter une IHM dans 3 environnements différents : Desktop GUI, terminal et web.
|
||||
*** [[https://www.qt.io/qt-for-python][Pyside]]
|
||||
Bindings python pour Qt.
|
||||
** CLI
|
||||
*** [[https://typer.tiangolo.com/https://typer.tiangolo.com/][Typer]]
|
||||
** Text UI
|
||||
*** [[id:6cc56ee4-6d42-4d50-beb3-bb22a98298dd][textual]]
|
||||
|
||||
|
||||
* Outils
|
||||
** Analyseur statique de code
|
||||
*** [[id:1d258869-5421-496a-b296-2d157ebdf3b6][mypy]]
|
||||
*** [[id:113a938e-3fb2-45cb-ae6e-41801418139b][bandit]]
|
||||
** Automatisation de tests
|
||||
*** [[https://nox.thea.codes/en/stable/][Nox]]
|
||||
Outil en ligne de commande permettant d'automatiser les tests dans multiples environnements Python. Comme Tox, à la
|
||||
différence, que la configuration est effectuée depuis un fichier Python (et non pas de configuration).
|
||||
*** [[https://tox.wiki/en/latest/][Tox]]
|
||||
Outil en ligne de commande permettant d'automatiser les tests dans multiples environnements Python.
|
||||
** Couverture de code
|
||||
*** [[https://github.com/plasma-umass/slipcover][Slipcover]]
|
||||
Outil de mesure de couverture de code plus rapide que [[https://github.com/nedbat/coveragepy][coverage.py]].
|
||||
** Debugger
|
||||
*** [[https://github.com/ionelmc/python-manhole][Manhole]]
|
||||
Service (interface via une socket Unix permettant l'accès à un REPL) permettant l'inspection d'un programme en cours d'exécution.
|
||||
** Formatter
|
||||
*** [[https://github.com/hhatto/autopep8][autopep8]]
|
||||
Utilitaire formattant le code afin de respecter la [[https://www.python.org/dev/peps/pep-0008/][PEP8]] guideline. Il est basé sur l'analyse de code effectuée par
|
||||
[[https://github.com/PyCQA/pycodestyle][pycodestyle]]. Autopep8 ne modifie que les espaces contenus dans le code (l'option ~--aggressive~ permet d'accroitre le
|
||||
pouvoir d'autopep8 et le laisser modifier le code).
|
||||
[[https://github.com/PyCQA/pycodestyle][pycodestyle]]. ~Autopep8~ ne modifie que les espaces contenus dans le code (l'option ~--aggressive~ permet d'accroître le
|
||||
pouvoir d'~autopep8~ et le laisser modifier le code).
|
||||
*** [[https://github.com/PyCQA/isort][isort]]
|
||||
Outil classant les imports par ordre alphabétique, les séparant par section et par type.
|
||||
*** [[https://black.readthedocs.io/en/stable/][Black]]
|
||||
Formatter n'appliquant que le style [[https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html][/black/]]. Il accepte la même synthaxe de contrôle que YAPF.
|
||||
*** [[https://github.com/google/yapf][YAPF]]
|
||||
En plus de vérifier la conformité avec la [[https://www.python.org/dev/peps/pep-0008/][PEP8]], YAPF formatte le code afin de respecter un style (approche basée sur
|
||||
~clang-format~ et similaire à ~gofmt~).
|
||||
*** [[https://black.readthedocs.io/en/stable/][Black]]
|
||||
Formatter n'appliquant que le style [[https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html][/black/]]. Il accepte la même synthaxe de contrôle que YAPF.
|
||||
** Générateur de données
|
||||
*** [[https://github.com/lk-geimfari/mimesis][Memesis]]
|
||||
Génération de données pouvant être utilisées pour:
|
||||
* Remplir une base de données de test,
|
||||
* Créer une faux /API endpoint/,
|
||||
* Créer des fichiers JSON ou XML d'après une structure arbitraire.
|
||||
*** [[https://github.com/joke2k/faker][Faker]]
|
||||
Génération de données.
|
||||
** Gestion dépendances
|
||||
*** [[id:01f24d29-e833-4bfa-acb0-95140800d081][poetry]]
|
||||
** Mockup
|
||||
*** [[https://github.com/spulec/freezegun][FreezeGun]]
|
||||
Mockup du module [[https://docs.python.org/fr/3/library/datetime.html][datetime]] permettant de simuler des changements de temps.
|
||||
*** [[https://github.com/getsentry/responses][Responses]]
|
||||
Mockup du module [[https://docs.python-requests.org/en/latest/][Requests]] permettant de simuler les réponses d'un serveur HTTP.
|
||||
** Profiling
|
||||
*** [[https://docs.python.org/3/library/profile.html#][cProfile]]
|
||||
Programme fournissant des /deteministic profiling/ de programmes (indique le nombre d'appel de chaque
|
||||
méthode et le temps passé).
|
||||
*** [[https://github.com/bloomberg/memray][Menray]]
|
||||
/Memory profiler/ traçant les allocations mémoire dans le code Python, les modules extensions et l'interpréteur.
|
||||
*** [[https://jiffyclub.github.io/snakeviz/][SnakeViz]]
|
||||
Visualisation des rapports de /cProfile/ (web browser).
|
||||
*** [[https://github.com/brandtbucher/specialist][Specialist]]
|
||||
Outil permettant d'indiquer le code optimisé par la spécialisation du bécote (cf. [[https://peps.python.org/pep-0659/][PEP 659 – Specializing Adaptive Interpreter]]).xo
|
||||
*** [[https://github.com/nvdv/vprof][vprof]]
|
||||
Profiling de programmes python permettant de surveiller le temps d'exécution et l'usage mémoire.
|
||||
~vprof -c hpm "<cmd>"~
|
||||
** Test de charge
|
||||
*** [[https://github.com/locustio/locust][Locust]]
|
||||
Outil permettant de tester la tenue en charge d'applications (initialement web servers).
|
||||
|
||||
** Traceur d'exécution de code
|
||||
*** [[https://github.com/ionelmc/python-hunter][Python-hunter]]
|
||||
Traçage des appels de fonctions, du code exécuté et des valeurs retournées (vs. smiley, pytrace, PySnooper).
|
||||
|
||||
* Implémentations
|
||||
** CPython
|
||||
Implémentation de référence du language Python.
|
||||
*** Développement de CModules
|
||||
**** Références
|
||||
* [[https://pythondev.readthedocs.io/][Python development notes - Victor Stinner]]
|
||||
*** Debug
|
||||
Activation du mode développeur ~python -X dev~ ou ~PYTHONDEVMODE=1 python~ (cf. [[https://docs.python.org/dev/library/devmode.html][Python Development Mode]]).
|
||||
|
||||
** Cinder
|
||||
Implémentation CPython optimisée par Instagram :
|
||||
* [[https://engineering.fb.com/2022/05/02/open-source/cinder-jits-instagram/][Jit]]
|
||||
|
||||
|
||||
* Modules intéressants
|
||||
** Bases de données
|
||||
*** [[https://spark.apache.org/docs/latest/api/python/][PySpark]]
|
||||
Binding Python a /Apache Spark/ permettant le traitement de bases de données massives, lorsque /Pandas/ devient trop
|
||||
lent.
|
||||
** Benchmarking
|
||||
*** [[id:4e351659-8a96-44af-bacb-f548ea35913e][timethese]]
|
||||
** CSV
|
||||
*** [[https://csvkit.readthedocs.io/en/latest/index.html][csvkit]]
|
||||
Ensemble d'outils en ligne de commande pour convertir en csv et pour les manipuler.
|
||||
** Graphique
|
||||
*** [[https://github.com/tfardet/mpl_chord_diagram][mpl_chord_diagram]]
|
||||
Génération de [[https://en.wikipedia.org/wiki/Chord_diagram_(information_visualization)][Chord diagrams]] avec /matplotlib/.
|
||||
*** [[https://networkx.org/][networkX]]
|
||||
Représentation de graphs.
|
||||
*** [[https://github.com/pwaller/pyfiglet][pyfiglet]]
|
||||
Représentation de texte sous forme d'ASCII art font.
|
||||
** Logs
|
||||
*** [[https://github.com/itamarst/eliot][eliot]]
|
||||
Génération de logs sous forme d'arbre.
|
||||
*** [[https://www.structlog.org/en/stable/index.html][structlog]]
|
||||
Formattage de logs.
|
||||
** Manipulation de classes
|
||||
*** [[https://github.com/MagicStack/immutables][Immutables]]
|
||||
Création de tables de hashage /immutables/.
|
||||
*** [[https://www.attrs.org/en/stable/][attrs]]
|
||||
Création de classes en évitant l'écriture du /boilerplate code/ (possibilité de créer des objets /immutables/).
|
||||
** Médias
|
||||
*** [[https://github.com/ytdl-org/youtube-dl][youtube-dl]]
|
||||
Téléchargement de vidéo depuis youtube, utilisé par mpv.
|
||||
*** [[https://github.com/goldsmith/Wikipedia][wikipedia]]
|
||||
Wrapper permettant l'accès au contenu de wikipedia.
|
||||
** Sérialization/déserialization
|
||||
*** [[https://github.com/ICRAR/ijson][ijson]]
|
||||
Parser JSON ne nécessitant pas que l'ensemble de la donnée soit chargée pour la parser (optimisation de la mémoire
|
||||
consommée, cf. [[https://pythonspeed.com/articles/json-memory-streaming/][JSON memory streaming - Pythonspeed]]).
|
||||
** Stockage des données
|
||||
*** [[https://github.com/theskumar/python-dotenv][dotenv]]
|
||||
** Surveillance de fichers
|
||||
*** [[https://watchfiles.helpmanual.io/][watchfiles]]
|
||||
Surveillance de fichiers basé sur la librarie Rust /Notify/.
|
||||
** Vulnérabilités/Cyber
|
||||
*** [[id:ba4c7c25-ee27-4b5e-8ef7-ba2ecc34f127][defusedxml]]
|
||||
** Web-scaping
|
||||
*** [[https://scrapy.org/][scrapy]]
|
||||
Framework d'extraction de données depuis des site web.
|
||||
|
||||
|
||||
* Modules amustants
|
||||
*** [[https://github.com/gahjelle/pythonji][pythonji]]
|
||||
Utilisation d'emojis pour l'écriture de code en Python
|
||||
|
||||
|
||||
* Performances
|
||||
** [[id:b9f392bd-bd45-4e9e-94ec-b19caedff86f][List vs tuple]]
|
||||
** [[id:26e1fdfb-1f8e-4c62-a08f-468a56ab03c8][Peephole optimization]]
|
||||
** [[id:c0d562c7-9d2f-4f35-b7b1-f6b6ca5273f9][Interning optimization]]
|
||||
** [[id:05864d6a-7a05-4c11-af14-4faebfdd1926][L'attribut de classe __slots__]]
|
||||
|
||||
* Génération et déploiement
|
||||
** Génération d'un artifact distribuable depuis le code source
|
||||
* Utilisation de [[https://setuptools.pypa.io/en/latest/][setuptools]].
|
||||
* Template de fichier [[https://github.com/pypa/sampleproject/blob/main/setup.py][setup.py]].
|
||||
** Stockage et distribution de l'artifact
|
||||
* Utilisation de [[https://pip.pypa.io/en/stable/][pip]].
|
||||
*** Les fichiers ~requirements.txt~
|
||||
* Il peut être intéressant de produire différents fichiers ~requirements.txt~ selon l'usage souhaité:
|
||||
* ~/requirements/app.txt~ pour les dépendances nécessaires à l'exécution du code,
|
||||
* ~/requirements/test.txt~ pour les dépendances nécessaires aux tests du code.
|
||||
* Dans un environnement de dev virtualisé, la commande ~pip freeze~ permet d'obtenir l'ensemble des dépendances et
|
||||
leurs version, récursivement.
|
||||
* [[https://github.com/jazzband/pip-tools][Pip-tools]] propose des outils permettant de simplifier la gestion des dépendances:
|
||||
* ~pip-compile --generate-hashes -o ./requirements.txt~ permet la génération de fichiers ~requirements.txt~ depuis les ~setup.py~ ou ~requirements.in~ d'un package,
|
||||
* La génération de hashes (option ~generate-hashes~) permet la vérification, lors de l'installation des dépendances,
|
||||
d'en vérifier la non altération (par rapport au paquet utilisé lors de la génération de notre package),
|
||||
* ~pip-compile --generate-hashes --extra dev -o ./requirements_dev.txt~ permet la génération d'un fichier
|
||||
~requirements_dev.txt~ comprenant les dépendances identifiées par les fichiers ~install_requires~ et
|
||||
~extras_require[dev]~.
|
||||
* [[https://devpi.net/docs/devpi/devpi/stable/+d/index.html#][devpi]] fournit un serveur PyPI-compatible (mirroir PyPI) et un utilitaire en ligne de commande pour les activités de mise en paquet,
|
||||
test (intégration avec Jenkins) et livraison.
|
||||
** Gestion des dépendances et de leur version et leur cloisement par projet
|
||||
* Utilisation de [[https://python-guide-pt-br.readthedocs.io/fr/latest/dev/virtualenvs.html][virtualenv]],
|
||||
* utiliser ~python -m pip~ et ~python -m venv~ (exécution du module en tant que script, au lieu de ~pip~ et ~virtualenv~) permet d'éviter les incohérences
|
||||
entre les différents répertoires des packages Python (cas lorsqu'un répertoire est présent dans le ~PYTHONPATH~ et qu'un autre l'est dans le ~PATH~).
|
||||
|
||||
* Optimisations
|
||||
** Création automatique de constantes numériques lors de la génération du bytecode
|
||||
#+BEGIN_SRC python :results output
|
||||
y = x * 5 / 9 # Une multiplcation par un entier, suivie par une division par un entier
|
||||
y = x * (5 / 9) # Le ratio 5 / 9 est calculé lors de la génération du bytecode associé à la ligne : une seule multiplication par un flottant lors de l'exécution de l'opération
|
||||
#+END_SRC
|
||||
A partir de Python3.11, les opérations entre types identiques (ie: int+int) peuvent être spécialisées (cf. [[https://www.youtube.com/watch?v=tNs18GDmAfg][Python Perf: Specializing, Adaptive Interpreter - Talk Python Live Stream - YouTube]] - augmentation des perfs).
|
||||
|
||||
* Tips
|
||||
** [[id:24408701-21d8-4f4e-aed9-c58746df2244][Différence entre les opérateurs + et +=]]
|
||||
** [[id:a32ab138-f9a8-4d61-9c09-97953c5a0a92][type == object]]
|
||||
** [[id:16d16a4b-6a4c-4597-a45f-1a99f2cb9f29][Any et all d'un iterable vide]]
|
||||
** [[id:e9a0cb94-ee68-4dfd-9013-c83ce2a18481][Ordre de résolution des attributs]]
|
||||
** [[id:279b5e79-6918-432c-85fa-2fbefc06619a][Attribut imag des types numériques]]
|
||||
** [[id:831fbfd2-c668-4099-b2d7-ecae734b9ec4][Evaluation tardive]]
|
||||
** [[id:f7c05933-90e6-4a9c-acd5-1f0baf62f07f][Arrondir les flottants en python]]
|
||||
** [[id:4ef76164-0e67-410a-8d26-b03071a0cc41][Compter la fréquence des éléments d'une liste]]
|
||||
** [[id:cb3c63b9-6452-4016-9b2f-a25784941d5d][List vs deque]]
|
||||
** [[id:9bdede16-5137-4393-a027-a5afbffd1618][Génération chaine de caractères aléatoires]]
|
||||
** [[id:cb3c63b9-6452-4016-9b2f-a25784941d5d][List vs deque]]
|
||||
** [[id:e9adeaaa-701a-4473-a30b-94f1e744c6d1][Obtenir la clé d'un dictionnaire pour laquelle la valeur est la plus petite]]
|
||||
** [[id:fa7e728b-dd2a-4d30-8f4b-e87813dc5f33][Modifier le style du texte affiché sur une console]]
|
||||
** [[id:20753ab5-70c3-4c8f-b261-56832cd5392c][Trouver le premier élément d'un iterable satisfaisant avec any]]
|
||||
|
||||
* Howtos
|
||||
* [[https://towardsdatascience.com/how-to-make-gifs-in-python-664d15ed4256][How to make GIFs in Python - Medium]]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
:PROPERTIES:
|
||||
:ID: 7bae5645-d19d-41c3-aafe-7c80c2a90789
|
||||
:mtime: 20211230161355
|
||||
:mtime: 20220604121806
|
||||
:ctime: 20211230160756
|
||||
:END:
|
||||
#+title: Emacs
|
||||
@@ -11,3 +11,15 @@
|
||||
|
||||
* Modes
|
||||
** [[id:59e3160b-39bc-4e2e-ab0a-79d58ac11804][Org]]
|
||||
** [[id:22c81d3d-29cc-4b49-8e94-bf8a7f8cb9b9][Magit]]
|
||||
|
||||
* Libraries
|
||||
** [[https://github.com/Malabarba/elisp-bug-hunter][elisp-bug-hunter]]
|
||||
Debug des scripts /elisp/ de configuration, permet d'identifier l'origine de l'erreur.
|
||||
|
||||
* Dotemacs
|
||||
** [[https://github.com/Gavinok/emacs.d][Gavinok's dotemacs]]
|
||||
** [[https://github.com/rougier/dotemacs][Rougier's dotemacs]]
|
||||
** [[https://github.com/yiufung/dot-emacs][Yiufung's dotemacs]]
|
||||
Intéressant pour la configuration du mode /anki/.
|
||||
** [[https://github.com/Gavinok/rational-emacs][rational-emacs - Gavinok]]
|
||||
|
@@ -1,15 +1,29 @@
|
||||
:PROPERTIES:
|
||||
:ID: 26b04294-75e8-4043-a9a6-a20acd952963
|
||||
:mtime: 20211230210701
|
||||
:mtime: 20220526081400
|
||||
:ctime: 20211230210035
|
||||
:END:
|
||||
#+title: Flask
|
||||
#+filetags: :TODO:Python:Flask:
|
||||
|
||||
TODO
|
||||
* Introduction
|
||||
Flask est un micro-framework /open-source/ de développement web écrit en Python dont les caractéristiques sont les
|
||||
suivantes :
|
||||
* Noyau simple et extensible (multiples extensions),
|
||||
* Basé sur les modules :
|
||||
* [[https://werkzeug.palletsprojects.com/en/latest/][Werkzeug]] : librairie complète permettant de réaliser des applications web [[https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface][WSGI]],
|
||||
* [[https://palletsprojects.com/p/jinja/][Jinja2]] : Moteur de template pour le language Python.
|
||||
* Licence BSD,
|
||||
|
||||
* Modules
|
||||
* Extensions
|
||||
* [[id:0eaaef80-51f9-4670-96c8-6a911efe152e][Flask-admin]]
|
||||
* [[id:5f41e674-eb59-4d69-981b-46a18cf28452][Flask-security]]
|
||||
|
||||
* Performance
|
||||
Pour détecter les /bottlenecks/ :
|
||||
* [[https://werkzeug.palletsprojects.com/en/2.1.x/middleware/profiler/][Werkzeug profiler]] : Inspecteur basé sur /cProfile/ permettant de mesurer le temps passé dans chaque méthode.
|
||||
|
||||
* Référence
|
||||
* [[https://smirnov-am.github.io/flask-perf/][How to increase Flask performance - Alexey Smirnov]]
|
||||
** Tuturiels
|
||||
* [[https://github.com/tecladocode/rest-apis-flask-python][REST APIs with Flask and Python - Github]]
|
||||
|
@@ -1,6 +1,6 @@
|
||||
:PROPERTIES:
|
||||
:ID: dc2a8693-7158-4155-8eff-fc35a21a077d
|
||||
:mtime: 20220101184431
|
||||
:mtime: 20220519084452
|
||||
:ctime: 20220101172208
|
||||
:END:
|
||||
#+title: La méthode __missing__
|
||||
|
@@ -1,6 +1,6 @@
|
||||
:PROPERTIES:
|
||||
:ID: 171ce2f7-4028-47b0-b4e0-5a4a6ccb74ac
|
||||
:mtime: 20220104161040
|
||||
:mtime: 20230729082927
|
||||
:ctime: 20220104155310
|
||||
:END:
|
||||
#+title: Postgres
|
||||
@@ -12,4 +12,85 @@
|
||||
* Fonctionne sur Solaris, SunOS, Mac OS X, HP-UX, AIX, Linux, IRIX, Digital Unix, BSD, NetBSD, FreeBSD, OpenBSD, SCO unix, NeXTSTEP, UnixWare et toutes sortes d'Unix. Depuis la version 8.0, PostgreSQL fonctionne également nativement sur Windows.
|
||||
|
||||
* Interfaces utilisateur
|
||||
** [[id:0455921f-3ac0-437e-ba76-1afb3f6f85ea][Psql]]
|
||||
** CLI
|
||||
* [[id:0455921f-3ac0-437e-ba76-1afb3f6f85ea][Psql]]
|
||||
** Graphique
|
||||
* [[https://arctype.com/][ArcType]]
|
||||
* [[https://github.com/dbeaver/dbeaver][DBeaver]]
|
||||
|
||||
* Howto
|
||||
** Pour lister les utilisateurs
|
||||
#+BEGIN_SRC sql
|
||||
\du
|
||||
#+END_SRC
|
||||
|
||||
** Pour supprimer un utilisateur
|
||||
#+BEGIN_SRC shell
|
||||
sudo -u postgres dropuser -e <user>
|
||||
#+END_SRC
|
||||
** Pour supprimer une base de données
|
||||
#+BEGIN_SRC shell
|
||||
sudo -u postgres dropdb <database>
|
||||
#+END_SRC
|
||||
** Pour modifier le password d'un utilisateur (dans psql)
|
||||
#+BEGIN_SRC sql
|
||||
\password <user>
|
||||
#+END_SRC
|
||||
|
||||
* Profiling de requêtes (query plan)
|
||||
** Depuis [[id:0455921f-3ac0-437e-ba76-1afb3f6f85ea][Psql]]
|
||||
#+BEGIN_SRC sql
|
||||
EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS) SELECT _stops.kind, _stops.id, _stops.name, _stops.town_name, _stops.postal_region, _stops.xepsg2154, _stops.yepsg2154, _stops.version, _stops.created_ts, _stops.changed_ts, stops.id AS id_1, stops.latitude, stops.longitude, stops.transport_mode, stops.accessibility, stops.visual_signs_available, stops.audible_signs_available, stops.record_id, stops.record_ts, stop_areas.id AS id_2, stop_areas.type
|
||||
FROM _stops LEFT OUTER JOIN stops ON _stops.id = stops.id LEFT OUTER JOIN stop_areas ON _stops.id = stop_areas.id
|
||||
WHERE _stops.name ILIKE '%Chaville rive droite%'
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC
|
||||
Nested Loop Left Join (cost=148.62..250.06 rows=5 width=194) (actual time=1.213..1.346 rows=12 loops=1)
|
||||
Output: _stops.kind, _stops.id, _stops.name, _stops.town_name, _stops.postal_region, _stops.xepsg2154, _stops.yepsg2154, _stops.version, _stops.created_ts, _stops.changed_ts, stops.id, stops.latitude, stops.longitude, stops.transport_mode, stops.accessibility, stops.visual_signs_available, stops.audible_signs_available, stops.record_id, stops.record_ts, stop_areas.id, stop_areas.type
|
||||
Inner Unique: true
|
||||
Buffers: shared hit=123
|
||||
-> Nested Loop Left Join (cost=148.33..208.53 rows=5 width=182) (actual time=1.196..1.296 rows=12 loops=1)
|
||||
Output: _stops.kind, _stops.id, _stops.name, _stops.town_name, _stops.postal_region, _stops.xepsg2154, _stops.yepsg2154, _stops.version, _stops.created_ts, _stops.changed_ts, stops.id, stops.latitude, stops.longitude, stops.transport_mode, stops.accessibility, stops.visual_signs_available, stops.audible_signs_available, stops.record_id, stops.record_ts
|
||||
Inner Unique: true
|
||||
Buffers: shared hit=97
|
||||
-> Bitmap Heap Scan on public._stops (cost=148.04..166.99 rows=5 width=93) (actual time=1.172..1.219 rows=12 loops=1)
|
||||
Output: _stops.kind, _stops.id, _stops.name, _stops.town_name, _stops.postal_region, _stops.xepsg2154, _stops.yepsg2154, _stops.version, _stops.created_ts, _stops.changed_ts
|
||||
Recheck Cond: ((_stops.name)::text ~~* '%Chaville rive droite%'::text)
|
||||
Heap Blocks: exact=11
|
||||
Buffers: shared hit=63
|
||||
-> Bitmap Index Scan on name_idx_gin (cost=0.00..148.04 rows=5 width=0) (actual time=1.155..1.155 rows=12 loops=1)
|
||||
Index Cond: ((_stops.name)::text ~~* '%Chaville rive droite%'::text)
|
||||
Buffers: shared hit=52
|
||||
-> Index Scan using stops_pkey on public.stops (cost=0.29..8.31 rows=1 width=89) (actual time=0.005..0.005 rows=1 loops=12)
|
||||
Output: stops.id, stops.latitude, stops.longitude, stops.transport_mode, stops.accessibility, stops.visual_signs_available, stops.audible_signs_available, stops.record_id, stops.record_ts
|
||||
Index Cond: (stops.id = _stops.id)
|
||||
Buffers: shared hit=34
|
||||
-> Index Scan using stop_areas_pkey on public.stop_areas (cost=0.29..8.30 rows=1 width=12) (actual time=0.003..0.003 rows=0 loops=12)
|
||||
Output: stop_areas.id, stop_areas.type
|
||||
Index Cond: (stop_areas.id = _stops.id)
|
||||
Buffers: shared hit=26
|
||||
Planning:
|
||||
Buffers: shared hit=22
|
||||
Planning Time: 1.015 ms
|
||||
Execution Time: 1.521 ms
|
||||
(28 rows)
|
||||
|
||||
Time: 3.503 ms
|
||||
#+END_SRC
|
||||
|
||||
** Visualisation de Query plan
|
||||
Différents sites permettent de visualiser graphiquement les query plans:
|
||||
* Gratuits:
|
||||
* [[https://explain.dalibo.com/][PEV2 - Dalibo]]
|
||||
* Payants:
|
||||
* [[https://app.pgmustard.com/login][PgMustard]]
|
||||
|
||||
** Audit
|
||||
Possibilité de logger ou de stocker en base les ajout/modifications ou suppressions de donnéées:
|
||||
* logs: [[https://www.pgaudit.org/]]
|
||||
* En base: [[https://wiki.postgresql.org/wiki/Audit_trigger_91plus]] ([[https://github.com/2ndQuadrant/audit-trigger]])
|
||||
|
||||
* Références
|
||||
* [[https://stackoverflow.com/questions/45395538/postgres-md5-password-plain-password][Postgres: MD5 Password / Plain password - Github]]
|
||||
* [[https://www.postgresql.org/docs/current/sql-explain.html][Sql-explain - PostgreSQL]]
|
||||
|
@@ -1,12 +1,12 @@
|
||||
:PROPERTIES:
|
||||
:ID: 0455921f-3ac0-437e-ba76-1afb3f6f85ea
|
||||
:mtime: 20220104160506
|
||||
:mtime: 20221229101120
|
||||
:ctime: 20220104155517
|
||||
:END:
|
||||
#+title: Psql
|
||||
#+filetags: :postgre:database:
|
||||
|
||||
Interface en ligne de commande permettant la saisie de requêtes SQL, directement ou par l'utilisation de procédures
|
||||
Interface en ligne de commande permettant la saisie de requêtes PostgreSQL, directement ou par l'utilisation de procédures
|
||||
stockées.
|
||||
|
||||
* Commandes
|
||||
|
@@ -1,17 +1,27 @@
|
||||
:PROPERTIES:
|
||||
:ID: e7581fe3-f83f-4243-91ed-6ef7ade6a844
|
||||
:mtime: 20220130201008
|
||||
:mtime: 20220910172209
|
||||
:ctime: 20220109134723
|
||||
:END:
|
||||
#+title: Linux
|
||||
|
||||
* [[id:5943c76c-8b25-4cbd-b0b9-c819e5a490ba][cyber]]
|
||||
|
||||
* Distributions
|
||||
** [[id:393342ff-bf38-4472-8713-3de5ebe43eca][Guix]]
|
||||
|
||||
* Gestionnaire de paquets
|
||||
** [[id:4cb68913-62c6-43bb-835f-85237b2a8b40][apt]]
|
||||
|
||||
* Systèmes d'initialisation
|
||||
** [[id:af912c20-4752-44ba-bdc0-99451ac0cd10][systemd]]
|
||||
|
||||
* Gestionnaire de volumes logiques :
|
||||
** [[id:f202b810-0fba-4c90-bc4c-f8cbc001fe88][LVM]]
|
||||
|
||||
* Fonctionnalités
|
||||
** [[id:fad57303-ce0c-4ae4-9529-294f70ecfaa5][Inotify]]
|
||||
** Surveillance de fichiers
|
||||
*** [[id:fad57303-ce0c-4ae4-9529-294f70ecfaa5][Inotify]]
|
||||
|
||||
* Interpreteur de commandes
|
||||
** [[id:72eb2d10-5b92-4fb7-9e4e-1398bd933335][bash]]
|
||||
@@ -19,3 +29,6 @@
|
||||
* Utilitaires
|
||||
** Parsing de contenu json (lib+bin) : [[id:83908b49-3945-4dce-8b26-2a5e4636df13][jq]]
|
||||
** Transfert de données à un serveur (lib+bin) : [[id:5ea61eaa-7f37-464c-aa69-8251de8f81af][curl]]
|
||||
** Template utilisant les variables d'environnement : [[https://manpage.me/?q=envsubst][envsubst]]
|
||||
** Lecture de fichiers
|
||||
*** [[id:d5b19724-9559-44de-aef7-c4d57fb6dc95][batcat]]
|
||||
|
@@ -1,15 +1,29 @@
|
||||
:PROPERTIES:
|
||||
:ID: 5943c76c-8b25-4cbd-b0b9-c819e5a490ba
|
||||
:mtime: 20220130203043
|
||||
:mtime: 20220927121655
|
||||
:ctime: 20220130140137
|
||||
:END:
|
||||
#+title: cyber
|
||||
|
||||
* Les 4 critères fondamentaux de la sécurité de l'information
|
||||
** Confidentialité
|
||||
* Une information ne doit être accessible qu'à ceux qui y sont autorisés,
|
||||
* Plus l’information est ‘sensible’, plus la liste des personnes autorisées à y accéder est réduite (en général) et plus le besoin de confiance est grand,
|
||||
** Intégrité
|
||||
* Une information ne doit pouvoir être modifiée que par des personnes autorisées et selon un procédé défini.
|
||||
** Disponibilité
|
||||
* Une information ne doit être accessible et utilisable par son destinataire qu'à l’endroit et à l’heure prévue.
|
||||
** Traçabilité
|
||||
* L'état et les mouvements de l'information doivent être tracés.
|
||||
|
||||
* Solution de contrôle d'intégrité ou de scellement
|
||||
** Linux: [[id:262f233d-9ae9-4bd7-a8e9-cba392a2c1f6][AIDE]]
|
||||
|
||||
* Serveur
|
||||
** "Tarpit"
|
||||
*** [[id:1ed652bc-bdcc-4410-a207-fb470df29e71][endlessh]]
|
||||
** Anti-DoS
|
||||
*** [[id:00b1b480-0f0c-42a3-8952-4275bc10bc00][fail2ban]]
|
||||
** Tips
|
||||
*** [[id:9eedbc4b-a961-4057-b2d8-8f10845f0478][Vérification des cyphers suites acceptées par un serveur]]
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
:PROPERTIES:
|
||||
:ID: 6cc56ee4-6d42-4d50-beb3-bb22a98298dd
|
||||
:mtime: 20220130154530
|
||||
:mtime: 20220814131534
|
||||
:ctime: 20220130153624
|
||||
:END:
|
||||
#+title: textual
|
||||
@@ -13,6 +13,71 @@ Rich est une librairie Python permettant de :
|
||||
* Afficher des tables et du contenu markdown,
|
||||
* Appliquer une coloration synthaxique.
|
||||
|
||||
* Howto
|
||||
** Pour inspecter un objet (/rich.inspect method)
|
||||
#+BEGIN_SRC python :results output
|
||||
from rich import inspect
|
||||
|
||||
class Dummy:
|
||||
|
||||
def __init__(self):
|
||||
self.a = 'A'
|
||||
self.b = 123
|
||||
|
||||
inspect(vars)
|
||||
|
||||
inspect(Dummy())
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: ╭────────────────── <built-in function vars> ──────────────────╮
|
||||
: │ def vars(...) │
|
||||
: │ │
|
||||
: │ vars([object]) -> dictionary │
|
||||
: │ │
|
||||
: │ 29 attribute(s) not shown. Run inspect(inspect) for options. │
|
||||
: ╰──────────────────────────────────────────────────────────────╯
|
||||
: ╭────────── <class '__main__.Dummy'> ───────────╮
|
||||
: │ ╭───────────────────────────────────────────╮ │
|
||||
: │ │ <__main__.Dummy object at 0x7f55d6d2d7c0> │ │
|
||||
: │ ╰───────────────────────────────────────────╯ │
|
||||
: │ │
|
||||
: │ a = 'A' │
|
||||
: │ b = 123 │
|
||||
: ╰───────────────────────────────────────────────╯
|
||||
|
||||
** Formatter les logs
|
||||
#+BEGIN_SRC python :results output
|
||||
import logging
|
||||
from rich.logging import RichHandler
|
||||
|
||||
FORMAT = "%(message)s"
|
||||
logging.basicConfig(
|
||||
level="NOTSET",
|
||||
format=FORMAT,
|
||||
datefmt="[%X]",
|
||||
handlers=[RichHandler(rich_tracebacks=True)])
|
||||
|
||||
log = logging.getLogger("rich")
|
||||
|
||||
log.info("Logging set up.")
|
||||
|
||||
def division(a, b):
|
||||
log.debug(f"Dividing {a} by {b}.")
|
||||
try:
|
||||
return a / b
|
||||
except ZeroDivisionError:
|
||||
log.exception("Oh noes!")
|
||||
|
||||
division(3, 2)
|
||||
division(5, 0)
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
|
||||
|
||||
* Projets
|
||||
** [[https://github.com/Traumatism/ToastCord][ToastCord - Github]]
|
||||
** [[https://github.com/kraanzu/dooit][Dooit - Github]]
|
||||
|
||||
* Références
|
||||
* [[https://github.com/Textualize/textual][Textual - Github]]
|
||||
* [[https://github.com/Textualize/rich][Rich - Github]]
|
||||
|
62
20220206220528-arrondir_les_flottants_en_python.org
Normal file
@@ -0,0 +1,62 @@
|
||||
:PROPERTIES:
|
||||
:ID: f7c05933-90e6-4a9c-acd5-1f0baf62f07f
|
||||
:mtime: 20220528103954
|
||||
:ctime: 20220206220528
|
||||
:END:
|
||||
#+title: Arrondir les flottants en python
|
||||
#+filetags: :Python:
|
||||
|
||||
* Arrondir à l'entier le plus proche
|
||||
** Avec la fonction /built-in/ /round/
|
||||
#+BEGIN_SRC python :results output
|
||||
print(f"{round(7 / 2) = }")
|
||||
print(f"{round(3 / 2) = }")
|
||||
print(f"{round(5 / 2) = }")
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: round(7 / 2) = 4
|
||||
: round(3 / 2) = 2
|
||||
: round(5 / 2) = 2
|
||||
|
||||
~round(5 / 2)~ retourne 2 et non 3 car la fonction /built-in/ implémente l'[[https://fr.wikipedia.org/wiki/Arrondi_(math%C3%A9matiques)#Arrondi%20au%20pair%20le%20plus%20proche][arrondi au pair le plus proche]].
|
||||
|
||||
* Arrondir un nombre à l'entier inférieur
|
||||
#+BEGIN_SRC python :results output
|
||||
print(22 // 5)
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: 4
|
||||
|
||||
* Arrondir un noombre à l'entier supérieur
|
||||
** Arithmétique simple
|
||||
#+BEGIN_SRC python :results output
|
||||
n = 22
|
||||
div = 5
|
||||
print(f'{int(n/div) + (n % div>0) = }')
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: int(n/div) + (n % div>0) = 5
|
||||
|
||||
** Opérateur à étage // (ne fonctionne qu'avec les entiers)
|
||||
L'opérateur à étage // se comporte comme l'opérateur de division /, à la différence que le résultat est arrondi à
|
||||
l'entier inférieur :
|
||||
#+BEGIN_SRC python :results output
|
||||
print(22 // -5 * -1)
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: 5
|
||||
|
||||
** Méthode /numpy.ceil/
|
||||
#+BEGIN_SRC python :results output
|
||||
from numpy import ceil
|
||||
|
||||
print(int(ceil(22 / 5)))
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: 5
|
||||
|
||||
* Références
|
||||
* [[https://medium.com/@saint_sdmn/10-hardest-python-questions-98986c8cd309][10 Hardest Python Questions - Medium]]
|
||||
* [[id:f7c05933-90e6-4a9c-acd5-1f0baf62f07f][Arrondir les flottants en python]]
|
||||
* [[https://www.delftstack.com/fr/howto/python/python-round-up/][Arrondir un nombre en Python]]
|
12
20220217175029-mypy.org
Normal file
@@ -0,0 +1,12 @@
|
||||
:PROPERTIES:
|
||||
:ID: 1d258869-5421-496a-b296-2d157ebdf3b6
|
||||
:mtime: 20220327100104
|
||||
:ctime: 20220217175029
|
||||
:END:
|
||||
#+title: Mypy
|
||||
|
||||
* Description
|
||||
/Mypy/ est un outil permettant de vérifier statiquement les types annotés.
|
||||
|
||||
* Tips
|
||||
** [[id:e30a1965-83c2-4015-92b5-dc4c8b9d82bf][Utiliser le nom d'une classe dans sa propre définition]]
|
@@ -0,0 +1,54 @@
|
||||
:PROPERTIES:
|
||||
:ID: e30a1965-83c2-4015-92b5-dc4c8b9d82bf
|
||||
:mtime: 20220217181714
|
||||
:ctime: 20220217175257
|
||||
:END:
|
||||
#+title: Utiliser le nom d'une classe dans sa propre définition
|
||||
|
||||
* Introduction
|
||||
Il arrive de devoir utiliser le nom d'une classe lors de l'annotation d'une de ses méthodes, notamment lorsque des
|
||||
/classmethod/ sont utilisées pour retourner une nouvelle instance de la classe. Pour répondre à ce besoin, la [[https://www.python.org/dev/peps/pep-0563/][PEP563
|
||||
(Postponed Evaluation of Annotations)]] a été rédigée/acceptée/implémentée. La modification consiste en la conversion des
|
||||
annotations de méthodes en string :
|
||||
* Jusqu'à Python3.11, en ajoutant la ligne ~from __future__ import annotations~
|
||||
* Comportement par défaut à partir de la version 3.11.
|
||||
|
||||
* Howto
|
||||
** Sans /Postponed Evaluation of Annotations/
|
||||
#+BEGIN_SRC python :results output
|
||||
from typing import Type, TypeVar
|
||||
|
||||
DummyClassT = TypeVar('DummyClassT', bound='DummyClass')
|
||||
|
||||
class DummyClass:
|
||||
|
||||
@classmethod
|
||||
def from_raw(cls: Type[DummyClassT], xml: str) -> DummyClassT:
|
||||
pass
|
||||
|
||||
print(DummyClass.from_raw.__annotations__)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: {'cls': typing.Type[~DummyClassT], 'xml': <class 'str'>, 'return': ~DummyClassT}
|
||||
|
||||
** Avec /Postponed Evaluation of Annotations/
|
||||
#+BEGIN_SRC python :results output
|
||||
from __future__ import annotations
|
||||
|
||||
class DummyClass:
|
||||
|
||||
@classmethod
|
||||
def from_raw(cls, xml: str) -> DummyClass:
|
||||
pass
|
||||
|
||||
print(DummyClass.from_raw.__annotations__)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: {'xml': 'str', 'return': 'DummyClass'}
|
||||
|
||||
* Références
|
||||
* [[https://gdevops.gitlab.io/tuto_python/versions/3.10.0/pep_0563/pep_0563.html]]
|
||||
* [[https://www.python.org/dev/peps/pep-0563/][PEP563 (Postponed Evaluation of Annotations)]]
|
||||
* [[https://bugs.python.org/issue38605][[typing] PEP 563: Postponed evaluation of annotations: enable it by default in Python 3.11]]
|
105
20220226100700-matrix.org
Normal file
@@ -0,0 +1,105 @@
|
||||
:PROPERTIES:
|
||||
:ID: 2e51f7e7-cf37-45d3-b7c4-c136d4e3cc64
|
||||
:mtime: 20220313180139
|
||||
:ctime: 20220226100700
|
||||
:END:
|
||||
#+title: matrix
|
||||
|
||||
* Introduction
|
||||
* Protocole de communication ouvert (specs ouvertes) pour la communication en temps réel (messagerie).
|
||||
* Passerelle avec différents fournisseurs de services (xmpp, Skype, IRC, ...).
|
||||
* Sécurisé (chiffrement de bout en bout activé par défaut).
|
||||
* Décentralisé (possibilité d'héberger son propre serveur).
|
||||
* Distribué/fédéré: chaque participant conserve l'historique de ses conversations (réplication entre les différents serveurs).
|
||||
* Appels voix & vidéo basés sur WebRTC.
|
||||
* Contrairement à XMPP (envoi de messages), Matrix fonctionne comme git : synchronisation de serveurs (conversation complète).
|
||||
* Matrix is /transport agnostic/: JSON/HTTP pourrait être remplacé.
|
||||
|
||||
#+DOWNLOADED: https://upload.wikimedia.org/wikipedia/commons/b/bd/Diagramme_Matrix_fr.svg @ 2022-02-26 10:29:56
|
||||
#+ATTR_ORG: :width 400
|
||||
[[file:Introduction/Diagramme_Matrix_fr_2022-02-26_10-29-56.svg]]
|
||||
|
||||
* Long-term secret = private key.
|
||||
|
||||
* Les serveurs Home
|
||||
** API
|
||||
* Synchro des messages et de l'état des rooms entre serveurs, en temps réel.
|
||||
* Synchro de l'historique des messages sur d'autres serveurs (à la git pull) : en cas d'offline, le serveur peut
|
||||
récupérer les historiques auprès d'autres serveurs afin de combler le trou.
|
||||
* Récupérer le profil et la présence d'un utilisateur.
|
||||
** Implémentations
|
||||
* Synapse (implémentation de référence) en Python/twisted.
|
||||
* Dendrite (implémentation de 2nd génération - plus scalable/performant) en Go.
|
||||
* Conduit (simple/rapide/reliable) en Rust.
|
||||
* Construct (orienté performances avec un min de deps) en C++.
|
||||
|
||||
* Les serveurs d'application
|
||||
** API
|
||||
* Possède un accès privilégié à un serveur Home.
|
||||
* Peut souscrire au trafic d'un server.
|
||||
* Peut /mascarade/ comme un utilisateur virtuel.
|
||||
|
||||
** Serveurs d'intégration
|
||||
* Permet d'intégrer de nouveaux services.
|
||||
*** Exemples
|
||||
* Etherpad:
|
||||
* RSS bot:
|
||||
* Grafana: publication de dashboards grafana pour un affichage directement sur les clients.
|
||||
* Jitsi:
|
||||
* Matrix-content-scanner:
|
||||
|
||||
** Les bridges
|
||||
* Unifier différents /réseaux/ ensemble (ie: signal, IRC, ...).
|
||||
*** Types de bridges
|
||||
* /Bridgebot/:
|
||||
* /Puppeted/: L'usage du bridge est transparent pour les utilisateurs.
|
||||
|
||||
* Les clients
|
||||
** API client-server
|
||||
* Conçue pour être user-friendly.
|
||||
** Implémentations UI
|
||||
* Element (implémentation de référence avec le plus de features) pour WebApp/desktop(electron)/IOS/Android.
|
||||
* Ditto (réalisé avec React) pour IOS/Android.
|
||||
* Nio (réalisé avec Switch) pour IOS.
|
||||
* Pattle (réalisé avec flutter) pour IOS/Android.
|
||||
* FluttyChat.
|
||||
* Seaglass: client matrix pour IOS.
|
||||
* Spectral: client matrix desktop écrit en c++ avec QtQuick control.
|
||||
* Quaternion: client IM desktop écrit en c++ avec Qt5.
|
||||
* Nheko reborn: client matrix desktop écrit en c++17 avec Qt.
|
||||
* Mirage: client matrix desktop configurable et opérable avec le clavier (à la Emacs).
|
||||
* Fractal: client matrix desktop écrit en rust.
|
||||
** Implémentations console
|
||||
* weechat-matrix:
|
||||
* gomuks: client matrix pour terminal écrit en go.
|
||||
* matrixcli: client matrix en ligne de commande.
|
||||
* matrix-commander: client matrix cli simple supportant le chiffrement E2E et la vérif. emoji.
|
||||
* tchap: client développé par le gouvernement français (inclus l'intégration du matrix-content-server).
|
||||
|
||||
* Les espaces (TODO)
|
||||
* Public /space/: l'annuaire hiérarchisé et public de Matrix.org.
|
||||
* Restricted /space/: pour les organisations, permet de regrouper des /rooms/ dans un même domaine.
|
||||
* private /space/: pour un usage personnel
|
||||
|
||||
* P2P (TODO)
|
||||
|
||||
* OSS
|
||||
Matrix utilise les OSS suivants:
|
||||
* olm: Librairie implémentant un /double-ratchet/ (basé sur les specs de Signal).
|
||||
* [[https://gitlab.matrix.org/matrix-org/olm/blob/master/docs/megolm.md][megolm]]: Librairie réalisant un /ratchet/ crypto basé sur AES pour les communications de groupe.
|
||||
|
||||
* Inconvénients
|
||||
* Backward secrecy (/future secrecy/ ou /post-compromise security/, le vol de la clé privée d'un correspondant ne
|
||||
compromet pas la confidentialité des communications futures) faible (tant que la session n'est pas renouvellée).
|
||||
* [[https://fr.wikipedia.org/wiki/Confidentialit%C3%A9_persistante][Confidentialité persistante]] (/forward secrecy/ ou /perfect forward secrecy/, le vol de la clé privée d'un
|
||||
correspondant ne compromet pas la confidentialité des communications passées) faible (dépend de la fréquence de
|
||||
renouvellement des clés).
|
||||
|
||||
* Optimisations réalisées
|
||||
* Lazy loading members: Ne charger les métadonnées que des personnes communiquant dans la /room/ (réduction de la RAM consommée).
|
||||
|
||||
* Références
|
||||
* [[https://fr.wikipedia.org/wiki/Matrix_(protocole)][Wikipedia]]
|
||||
* [[https://www.youtube.com/watch?v=cD8xbci4wAY][Matrix - Open, Secure, Decentralised, Real-Time Communication Across Networks - Oleg Fiksel]]
|
||||
* [[https://www.youtube.com/watch?v=9cjUzftDuoQ][Matrix in the French State What happens when a government adopts open source & open standards for all its internal communication? by Matthew Hodgson]]
|
||||
* [[https://2021.commcon.xyz/talks/matrix-101][Matrix 101 - Thibault Martin]]
|
13
20220306172443-bandit.org
Normal file
@@ -0,0 +1,13 @@
|
||||
:PROPERTIES:
|
||||
:ID: 113a938e-3fb2-45cb-ae6e-41801418139b
|
||||
:mtime: 20220306172631
|
||||
:ctime: 20220306172443
|
||||
:END:
|
||||
#+title: bandit
|
||||
|
||||
* Introduction
|
||||
Bandit est un OSS détectant les failles de sécurité via l'analyse statique de code python.
|
||||
|
||||
* Références
|
||||
* [[https://github.com/PyCQA/bandit][Github]]
|
||||
|
50
20220306172805-defusedxml.org
Normal file
@@ -0,0 +1,50 @@
|
||||
:PROPERTIES:
|
||||
:ID: ba4c7c25-ee27-4b5e-8ef7-ba2ecc34f127
|
||||
:mtime: 20220522180309
|
||||
:ctime: 20220306172805
|
||||
:END:
|
||||
#+title: defusedxml
|
||||
|
||||
* Introduction
|
||||
Module proposant une sourcouche protégeant contre les vulnérabilités de certains modules python gérant des données XML.
|
||||
|
||||
Par exemple :
|
||||
#+BEGIN_SRC python
|
||||
from xml.etree.ElementTree import parse
|
||||
et = parse(xmlfile)
|
||||
#+END_SRC
|
||||
|
||||
Serait à mettre à jour ainsi :
|
||||
#+BEGIN_SRC python
|
||||
from defusedxml.ElementTree import parse
|
||||
et = parse(xmlfile)
|
||||
#+END_SRC
|
||||
|
||||
* Liste des vulnérabilités et fonctionnalités
|
||||
|
||||
| Vulnérabilité | sax | etree | minidom | pulldom | xmlrpc | [[id:b18fe210-fac3-4f63-8041-4b686c64ee6a][lxml]] | genshi |
|
||||
|--------------------------------------------+-------+-------+---------+---------+--------+------------+--------|
|
||||
| [[id:7b090d0a-b96b-4d40-afec-2155a6909935][xml billion laughs]] | ✔ | ✔ | ✔ | ✔ | ✔ | ✖ (1) | ✖ (5) |
|
||||
| quadratic blowup | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | ✖ (5) |
|
||||
| [[id:869e88ed-fe68-47b5-a911-e27cf3927f66][XML external entity expension]] (remote) | ✔ | ✖ (3) | ✖ (4) | ✔ | ✖ | ✖ (1) | ✖ (5) |
|
||||
| [[id:869e88ed-fe68-47b5-a911-e27cf3927f66][XML external entity expension]] (local file) | ✔ | ✖ (3) | ✖ (4) | ✔ | ✖ | ✔ | ✖ (5) |
|
||||
| DTD retrieval | ✔ | ✖ | ✖ | ✔ | ✖ | ✖ (1) | ✖ |
|
||||
| gzip bomb | ✖ | ✖ | ✖ | ✖ | ✔ | Partly (2) | ✖ |
|
||||
| xpath support (7) | ✖ | ✖ | ✖ | ✖ | ✖ | ✔ | ✖ |
|
||||
| xsl(t) support (7) | ✖ | ✖ | ✖ | ✖ | ✖ | ✔ | ✖ |
|
||||
| xinclude support (7) | ✖ | ✔ (6) | ✖ | ✖ | ✖ | ✔ (6) | ✔ |
|
||||
| C library | expat | expat | expat | expat | expat | libxml2 | expat |
|
||||
|
||||
|
||||
1. /lxml/ est protégé contre les attaques /billion laughs/ et ne fait pas de recherche réseau (/network lookups/) par défaut.
|
||||
2. /libxml2/ et /lxml/ ne sont pas directement vulnérables aux /gzip decompression bombs/ mais ne vous protège pas contre
|
||||
par ailleurs.
|
||||
3. /xml.etree/ ne développe pas les entités et déclenche une /ParserError/ lorsqu'une entité apparait.
|
||||
4. /minicom/ ne développe pas les entités et retourne une entitée textuelle non développée.
|
||||
5. /genshi.input/ (v0.6) ne développe pas les entités et déclenche une /ParserError/ lorsqu'une entité apparait.
|
||||
6. La librarie apporte un support limité à /XInclude/ (mécanisme de fusion) mais requiert une étape additionnelle pour
|
||||
réaliser l'inclusion.
|
||||
7. Il s'agit de fonctionnalités mais peuvent introduire des failles supplémentaires.
|
||||
|
||||
* Références
|
||||
* [[https://github.com/tiran/defusedxml][Github]]
|
9
20220306173625-lxml.org
Normal file
@@ -0,0 +1,9 @@
|
||||
:PROPERTIES:
|
||||
:ID: b18fe210-fac3-4f63-8041-4b686c64ee6a
|
||||
:mtime: 20220306173658
|
||||
:ctime: 20220306173625
|
||||
:END:
|
||||
#+title: lxml
|
||||
|
||||
* Introduction
|
||||
Module Python permettant la manipulation de données au format XML.
|
35
20220306181623-xml_billion_laughs.org
Normal file
@@ -0,0 +1,35 @@
|
||||
:PROPERTIES:
|
||||
:ID: 7b090d0a-b96b-4d40-afec-2155a6909935
|
||||
:mtime: 20220306182044
|
||||
:ctime: 20220306181623
|
||||
:END:
|
||||
#+title: XML billion laughs
|
||||
|
||||
* Introduction
|
||||
* Attaque de type déni de service visant les parseurs XML.
|
||||
* Peut aussi servir de vecteur pour faciliter les attaques par /dépassement de tampon/.
|
||||
|
||||
* Principe
|
||||
Le standard XML permet la déclaration récursive d'entités XML sans aucune limite de profondeur ou de longueur des
|
||||
éléments. L'attaquant peut donc donner une très grande longueur au résultat censé être produit lors de l'analyse
|
||||
lexicale du document XML. Ainsi, le déni de service est provoqué par le parseur XML tentant de lire le document avec
|
||||
toutes ses entités décrites de manière récursive, ce qui peut potentiellement provoquer un dépassement mémoire.
|
||||
|
||||
* Exemple
|
||||
#+BEGIN_SRC xml
|
||||
<!DOCTYPE root [
|
||||
<!ENTITY lol "lol">
|
||||
<!ENTITY lol2 "&lol; &lol;">
|
||||
<!ENTITY lol3 "&lol2; &lol2;">
|
||||
<!ENTITY lol4 "&lol3; &lol3;">
|
||||
<!ENTITY lol5 "&lol4; &lol4;">
|
||||
…
|
||||
<!ENTITY lol128 "&lol127; &lol127;">
|
||||
]>
|
||||
<root>&lol128;</root>
|
||||
#+END_SRC
|
||||
|
||||
* Références
|
||||
* [[https://en.wikipedia.org/wiki/Billion_laughs_attack][Wikipedia]]
|
||||
|
||||
|
28
20220306184527-xml_external_entity_expension.org
Normal file
@@ -0,0 +1,28 @@
|
||||
:PROPERTIES:
|
||||
:ID: 869e88ed-fe68-47b5-a911-e27cf3927f66
|
||||
:mtime: 20220307073210
|
||||
:ctime: 20220306184527
|
||||
:END:
|
||||
#+title: XML external entity expension
|
||||
|
||||
* Introduction
|
||||
* Attaque visant les parseurs XML,
|
||||
* Permettant:
|
||||
* La divulgation de données,
|
||||
* Le déni de service,
|
||||
* /Server-side request forgery (SSRF)/.
|
||||
|
||||
* Principe
|
||||
Le standard XML 1.0, définissant la structure d'un document XML, introduit le concept d'/entity/ qui consiste en une
|
||||
unité de stockage d'un certain type. Quelques types d'/entity/
|
||||
|
||||
There are a few different types of entities, external general/parameter parsed entity often shortened to external entity, that can access local or remote content via a declared system identifier. The system identifier is assumed to be a URI that can be dereferenced (accessed) by the XML processor when processing the entity. The XML processor then replaces occurrences of the named external entity with the contents dereferenced by the system identifier. If the system identifier contains tainted data and the XML processor dereferences this tainted data, the XML processor may disclose confidential information normally not accessible by the application. Similar attack vectors apply the usage of external DTDs, external style sheets, external schemas, etc. which, when included, allow similar external resource inclusion style attacks.
|
||||
|
||||
Attacks can include disclosing local files, which may contain sensitive data such as passwords or private user data, using file: schemes or relative paths in the system identifier. Since the attack occurs relative to the application processing the XML document, an attacker may use this trusted application to pivot to other internal systems, possibly disclosing other internal content via http(s) requests or launching a CSRF attack to any unprotected internal services. In some situations, an XML processor library that is vulnerable to client-side memory corruption issues may be exploited by dereferencing a malicious URI, possibly allowing arbitrary code execution under the application account. Other attacks can access local resources that may not stop returning data, possibly impacting application availability if too many threads or processes are not released.
|
||||
|
||||
Note that the application does not need to explicitly return the response to the attacker for it to be vulnerable to information disclosures. An attacker can leverage DNS information to exfiltrate data through subdomain names to a DNS server under their control.
|
||||
|
||||
|
||||
|
||||
* Références
|
||||
* [[https://en.wikipedia.org/wiki/XML_external_entity_attack][Wikipedia]]
|
108
20220319091825-anki.org
Normal file
@@ -0,0 +1,108 @@
|
||||
|
||||
:PROPERTIES:
|
||||
:ID: 97d8c2d9-a539-4f0b-ad2e-953bf7845e8c
|
||||
:mtime: 20220327110913
|
||||
:ctime: 20220319091825
|
||||
:END:
|
||||
#+title: Anki
|
||||
|
||||
* Introduction
|
||||
* logiciel libre permettant d'apprendre/réviser des cartes-mémoires grâce à la répétition espacée,
|
||||
* Anki (暗記) signifie « mémorisation » en japonais.
|
||||
* S'appuie sur l'algorithme SM2 à la fin des années 1980. L'algorithme a été modifié pour redéfinir l'ordre
|
||||
d'apparition des cartes par priorité.
|
||||
* Permet de créer des cartes-mémoires contenant plusieurs champs sur une même face.
|
||||
* Sauvegarde de son apprentissage en ligne.
|
||||
* Histogrammes et statistiques d'apprentissage.
|
||||
* Les cartes et données d'apprentissages stockées au format SQLite.
|
||||
* L'algorithme de la répétition espacée permet de réviser plus souvent les cartes les moins connues. Fondé sur la
|
||||
courbe de l'oubli d'Hermann Ebbinghaus.
|
||||
* Chaque utilisateur peut créer ses paquets de cartes facilement.
|
||||
* De nombreux add-ons (greffons), modifiant l'aspect d'Anki ou lui ajoutant des fonctions.
|
||||
|
||||
* Installer son serveur Anki
|
||||
** Howto
|
||||
*** On the server:
|
||||
#+BEGIN_SRC shell
|
||||
# Get last version source code.
|
||||
cd /opt/
|
||||
ROOT=/opt/anki-sync-server
|
||||
mkdir ${ROOT}
|
||||
chown ubuntu ${ROOT}
|
||||
git clone https://github.com/ankicommunity/anki-sync-server.git
|
||||
cd ${ROOT}
|
||||
git checkout tags/v2.3.0
|
||||
|
||||
# Prépare virtual environment.
|
||||
PATH=/home/ubuntu/.local/bin:$PATH
|
||||
virtualenv .
|
||||
. bin/activate
|
||||
make init
|
||||
|
||||
# Create first user
|
||||
./src/ankisyncctl.py adduser <user>
|
||||
|
||||
# Edit daemon config file.
|
||||
CONFIG_PATH=${ROOT}/src/ankisyncd.conf
|
||||
sed -i 's/port = 27701/port = 27702/' ${CONFIG_PATH}
|
||||
sed -i 's/host = 0.0.0.0/host = 127.0.0.1/' ${CONFIG_PATH}
|
||||
|
||||
# Configure ngingx
|
||||
cat >/etc/nginx/sites-available/anki-sync-server <<EOF
|
||||
server {
|
||||
server_name anki.adrien.run;
|
||||
|
||||
# Increase timeouts for XXL collections through slow bandwidth
|
||||
proxy_read_timeout 3000;
|
||||
proxy_connect_timeout 3000;
|
||||
proxy_send_timeout 3000;
|
||||
|
||||
# log files
|
||||
access_log /var/log/nginx/anki-sync-server.access.log;
|
||||
error_log /var/log/nginx/anki-sync-server.error.log;
|
||||
|
||||
# Handle / requests
|
||||
location / {
|
||||
proxy_http_version 1.0;
|
||||
proxy_pass http://127.0.0.1:27702/;
|
||||
client_max_body_size 222M;
|
||||
}
|
||||
}
|
||||
EOF
|
||||
ln -s /etc/nginx/sites-available/anki-sync-server /etc/nginx/sites-enabled/
|
||||
systemctl reload nginx
|
||||
|
||||
# Generate certificates signed by certbot
|
||||
certbot --nginx -d anki.adrien.run
|
||||
systemctl reload nginx
|
||||
|
||||
# Add systemd service
|
||||
cat>/etc/systemd/system/anki-sync-server.service <<EOF
|
||||
Description=Anki sync server
|
||||
After=syslog.target network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/anki-sync-server
|
||||
ExecStart=/opt/anki-sync-server/bin/python /opt/anki-sync-server/src/ankisyncd/__main__.py
|
||||
Restart=on-abort
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl enable anki-sync-server.service
|
||||
systemctl start anki-sync-server.service
|
||||
#+END_SRC
|
||||
|
||||
*** For AnkiDroid:
|
||||
Update configuration (in menu parameters/advanced/Custom sync server):
|
||||
* URL: https://anki.adrien.run
|
||||
* Media URL: https://anki.adrien.run/msync
|
||||
|
||||
*** For Anki2.1
|
||||
Cf. https://github.com/ankicommunity/anki-sync-server#anki-21
|
||||
|
||||
** Références
|
||||
* [[https://fr.wikipedia.org/wiki/Anki][Wikipedia]]
|
||||
* [[https://github.com/ankicommunity/anki-sync-server][Github]]
|
28
20220319131922-verrou_bash.org
Normal file
@@ -0,0 +1,28 @@
|
||||
:PROPERTIES:
|
||||
:ID: 7052d327-0b67-40f6-a581-46df621cddb9
|
||||
:mtime: 20220319133448
|
||||
:ctime: 20220319131922
|
||||
:END:
|
||||
#+title: verrou-bash
|
||||
|
||||
* Verrou (lock) en sh
|
||||
** Utilisation de /flock/
|
||||
#+BEGIN_SRC shell
|
||||
LOCK_PATH=/var/tmp/testlock.lock
|
||||
exec 100>${LOCK_PATH} || exit 1
|
||||
flock 100 || exit 1
|
||||
|
||||
echo "Doing some stuff…"
|
||||
echo "Sleeping for 30 seconds…"
|
||||
sleep 30
|
||||
|
||||
trap "rm -f ${LOCK_PATH}" EXIT
|
||||
#+END_SRC
|
||||
|
||||
Quelques options :
|
||||
* ~-w 10~ pour définir un timeout à ~flock~, ici 10 secondes.
|
||||
* ~-n~ pour que ~flock~ n'attende pas si le verrou est pris.
|
||||
|
||||
* Références
|
||||
* [[https://www.putorius.net/lock-files-bash-scripts.html][Using Lock Files for Job Control in Bash Scripts - Putorius]]
|
||||
* [[https://linux.die.net/man/1/flock][Man flock]]
|
37
20220327100232-elisp.org
Normal file
@@ -0,0 +1,37 @@
|
||||
:PROPERTIES:
|
||||
:ID: 33ef1e68-70ad-43c8-850d-4b8ed2c5ea16
|
||||
:mtime: 20220327102013
|
||||
:ctime: 20220327100232
|
||||
:END:
|
||||
#+title: Elisp
|
||||
|
||||
* Introduction
|
||||
Emacs Lisp est un dialecte du language /Lisp/ utilisé, entre autres, par les éditeurs /Emacs/ et /XEmacs/.
|
||||
|
||||
* Listes
|
||||
** Backquote `
|
||||
L'usage de /backquote/ avec une liste permet :
|
||||
* La convertir en chaine de caractères,
|
||||
#+BEGIN_SRC emacs-lisp :results verbatim
|
||||
`(a list of ,(+ 2 3) elements)
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: (a list of 5 elements)
|
||||
|
||||
* L'évaluation sélective d'éléments,
|
||||
#+BEGIN_SRC emacs-lisp :results verbatim
|
||||
(setq some-list '(2 3))
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: (2 3)
|
||||
|
||||
* La fusion de listes
|
||||
#+BEGIN_SRC emacs-lisp :results verbatim
|
||||
`(1 ,@some-list 4 ,@some-list)
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: (1 2 3 4 2 3)
|
||||
|
||||
* Références
|
||||
* [[https://emacstil.com/til/2022/01/05/elisp-what-does-backquote-do/][Elisp: What does backquote ` do ?]]
|
||||
* [[https://www.gnu.org/software/emacs/manual/html_node/eintr/][An Introduction to Programming in Emacs Lisp]]
|
31
20220327102701-lvm.org
Normal file
@@ -0,0 +1,31 @@
|
||||
:PROPERTIES:
|
||||
:ID: f202b810-0fba-4c90-bc4c-f8cbc001fe88
|
||||
:mtime: 20220327105541
|
||||
:ctime: 20220327102701
|
||||
:END:
|
||||
#+title: LVM
|
||||
|
||||
* Introduction
|
||||
La gestion par volumes logiques (/Logical Volume Management/) est :
|
||||
* Une méthode,
|
||||
* Un logiciel de gestion de l'utilisation des espaces de stockage d'un ordinateur.
|
||||
|
||||
Il permet de gérer de manière souple les espaces de stockage en ligne dans les systèmes d'exploitation de type UNIX.
|
||||
|
||||
#+DOWNLOADED: https://upload.wikimedia.org/wikipedia/commons/4/42/LVM1.jpg @ 2022-03-27 10:39:39
|
||||
[[file:Introduction/LVM1_2022-03-27_10-39-39.jpg]]
|
||||
|
||||
** Le volume physique (PV)
|
||||
Il s'agit d'un disque ou d'une partition, un espace de stockage réel (block device) géré par LVM.
|
||||
** Groupe de volumes (VG)
|
||||
Il s'agit d'un ensemble de volumes physiques (au moins 1 PV par VG).LVM requiert au moins 1 VG. Mettre plusieurs disques
|
||||
dans un même VG peut permettre « d'étaler » un système de fichiers sur plusieurs disques(//home/ sur 2 disques par
|
||||
exemple, dangereux en cas de perte d'un disque et moins performant que le RAID-0).
|
||||
** Volume logique (LV)
|
||||
Un LV est un espace « quelque part dans un groupe de volume » où l'on peut mettre un système de fichiers (remplaçant des
|
||||
partitions).
|
||||
|
||||
* Références
|
||||
* [[https://fr.wikipedia.org/wiki/Gestion_par_volumes_logiques][Wikipedia]]
|
||||
* [[https://doc.ubuntu-fr.org/lvm][Ubuntu]]
|
||||
* [[https://gist.github.com/kzap/7e5994dda6c01b19760a][kzap/create-lvm.sh]]
|
13
20220327105648-bash.org
Normal file
@@ -0,0 +1,13 @@
|
||||
:PROPERTIES:
|
||||
:ID: a877b82e-4925-41de-8903-8109dd98e773
|
||||
:mtime: 20220327105718
|
||||
:ctime: 20220327105648
|
||||
:END:
|
||||
#+title: Bash
|
||||
|
||||
* Introduction
|
||||
|
||||
** Lock: [[id:7052d327-0b67-40f6-a581-46df621cddb9][verrou-bash]]
|
||||
|
||||
* Références
|
||||
|
@@ -0,0 +1,79 @@
|
||||
:PROPERTIES:
|
||||
:ID: e9adeaaa-701a-4473-a30b-94f1e744c6d1
|
||||
:mtime: 20220416112424
|
||||
:ctime: 20220416105003
|
||||
:END:
|
||||
#+title: Obtenir la clé d'un dictionnaire pour laquelle la valeur est la plus petite
|
||||
|
||||
* Howto
|
||||
#+BEGIN_SRC python :results output
|
||||
from random import randint
|
||||
from timethese import cmpthese, pprint_cmp
|
||||
|
||||
data = {randint(0, 1000): randint(0, 1000) for i in range(100)}
|
||||
|
||||
def convert_to_lists():
|
||||
v=list(data.values())
|
||||
k=list(data.keys())
|
||||
return k[v.index(min(v))]
|
||||
|
||||
def dict_comprehension():
|
||||
d3={v:k for k,v in data.items()}
|
||||
return d3[min(d3)]
|
||||
|
||||
def filter_and_lambda():
|
||||
return list(filter(lambda t: t[1]==min(data.values()), data.items()))[0][0]
|
||||
|
||||
def filter_and_lambda2():
|
||||
m=min(data.values())
|
||||
return list(filter(lambda t: t[1]==m, data.items()))[0][0]
|
||||
|
||||
def list_comprehension():
|
||||
return [k for k,v in data.items() if v==min(data.values())][0]
|
||||
|
||||
def list_comprehension2():
|
||||
m=min(data.values())
|
||||
return [k for k,v in data.items() if v==m][0]
|
||||
|
||||
def using_min():
|
||||
return min(data, key=data.get)
|
||||
|
||||
def convert_to_lists_shortened():
|
||||
v=list(data.values())
|
||||
return list(data.keys())[v.index(min(v))]
|
||||
|
||||
def using_min_and_lambda():
|
||||
return min(data, key=lambda k: data[k])
|
||||
|
||||
tl = [convert_to_lists,
|
||||
dict_comprehension,
|
||||
filter_and_lambda,
|
||||
filter_and_lambda2,
|
||||
list_comprehension,
|
||||
list_comprehension2,
|
||||
using_min,
|
||||
convert_to_lists_shortened,
|
||||
using_min_and_lambda]
|
||||
|
||||
print(pprint_cmp(cmpthese(1000, tl)))
|
||||
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
#+begin_example
|
||||
Rate 0.convert_to_lists 7.convert_to_lists_shortened 6.using_min 5.list_comprehension2 1.dict_comprehension 8.using_min_and_lambda 3.filter_and_lambda2 4.list_comprehension 2.filter_and_lambda
|
||||
0.convert_to_lists 424342/s . 1% 52% 105% 178% 216% 312% 5414% 5745%
|
||||
7.convert_to_lists_shortened 419268/s -1% . 50% 103% 175% 213% 307% 5348% 5675%
|
||||
6.using_min 280002/s -34% -33% . 36% 84% 109% 172% 3538% 3757%
|
||||
5.list_comprehension2 206598/s -51% -51% -26% . 36% 54% 101% 2585% 2746%
|
||||
1.dict_comprehension 152444/s -64% -64% -46% -26% . 14% 48% 1881% 2000%
|
||||
8.using_min_and_lambda 134115/s -68% -68% -52% -35% -12% . 30% 1643% 1747%
|
||||
3.filter_and_lambda2 103036/s -76% -75% -63% -50% -32% -23% . 1239% 1319%
|
||||
4.list_comprehension 7696/s -98% -98% -97% -96% -95% -94% -93% . 6%
|
||||
2.filter_and_lambda 7260/s -98% -98% -97% -96% -95% -95% -93% -6% .
|
||||
#+end_example
|
||||
|
||||
* Références
|
||||
* [[https://docs.python.org/3/library/functions.html#min][Python]]
|
||||
* [[https://blog.finxter.com/how-to-get-the-key-with-minimum-value-in-a-python-dictionary/][Finxter]]
|
||||
* [[https://stackoverflow.com/questions/268272/getting-key-with-maximum-value-in-dictionary][Stackoverflow]]
|
96
20220416112952-timethese.org
Normal file
@@ -0,0 +1,96 @@
|
||||
:PROPERTIES:
|
||||
:ID: 4e351659-8a96-44af-bacb-f548ea35913e
|
||||
:mtime: 20220416113532
|
||||
:ctime: 20220416112952
|
||||
:END:
|
||||
#+title: timethese
|
||||
|
||||
* Introduction
|
||||
* Package permettant de mesurer les temps nécessaires à l'exécution de plusieurs méthodes et de les comparer.
|
||||
* Approche en 3 étapes :
|
||||
* Définition des méthodes à benchmarker,
|
||||
* Préparation et exécution des tests (usage de la classe /cmpthese/),
|
||||
* Formattage des résultas (pretty print).
|
||||
|
||||
* Installation
|
||||
#+BEGIN_SRC shell
|
||||
pip install timethese
|
||||
#+END_SRC
|
||||
|
||||
* Exemple
|
||||
#+BEGIN_SRC python :results output
|
||||
from timethese import cmpthese, pprint_cmp, timethese
|
||||
|
||||
xs = range(10)
|
||||
|
||||
|
||||
# 1. DEFINE FUNCTIONS
|
||||
|
||||
def map_hex():
|
||||
list(map(hex, xs))
|
||||
|
||||
|
||||
def list_compr_hex():
|
||||
list([hex(x) for x in xs])
|
||||
|
||||
|
||||
def map_lambda():
|
||||
list(map(lambda x: x + 2, xs))
|
||||
|
||||
|
||||
def map_lambda_fn():
|
||||
fn = lambda x: x + 2
|
||||
list(map(fn, xs))
|
||||
|
||||
|
||||
def list_compr_nofn():
|
||||
list([x + 2 for x in xs])
|
||||
|
||||
|
||||
# 2. FEED THE FUNCTIONS TO CMPTHESE
|
||||
|
||||
# AS DICT:
|
||||
|
||||
cmp_res_dict = cmpthese(
|
||||
10000,
|
||||
{
|
||||
"map_hex": map_hex,
|
||||
"list_compr_hex": list_compr_hex,
|
||||
"map_lambda": map_lambda,
|
||||
"map_lambda_fn": map_lambda_fn,
|
||||
"list_compr_nofn": list_compr_nofn,
|
||||
},
|
||||
repeat=3,
|
||||
)
|
||||
|
||||
|
||||
# OR AS LIST:
|
||||
|
||||
cmp_res_list = cmpthese(
|
||||
10000, [map_hex, list_compr_hex, map_lambda, map_lambda_fn, list_compr_nofn,], repeat=3,
|
||||
)
|
||||
|
||||
# 3. PRETTY PRINT THE RESULTS
|
||||
|
||||
print(pprint_cmp(cmp_res_dict))
|
||||
print(pprint_cmp(cmp_res_list))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
#+begin_example
|
||||
Rate list_compr_nofn map_hex map_lambda map_lambda_fn list_compr_hex
|
||||
list_compr_nofn 1889389/s . 21% 42% 45% 68%
|
||||
map_hex 1565635/s -17% . 18% 21% 40%
|
||||
map_lambda 1328914/s -30% -15% . 2% 18%
|
||||
map_lambda_fn 1298638/s -31% -17% -2% . 16%
|
||||
list_compr_hex 1121963/s -41% -28% -16% -14% .
|
||||
Rate 4.list_compr_nofn 0.map_hex 3.map_lambda_fn 2.map_lambda 1.list_compr_hex
|
||||
4.list_compr_nofn 1836243/s . 17% 37% 38% 73%
|
||||
0.map_hex 1568271/s -15% . 17% 18% 47%
|
||||
3.map_lambda_fn 1336453/s -27% -15% . 0% 26%
|
||||
2.map_lambda 1334377/s -27% -15% -0% . 25%
|
||||
1.list_compr_hex 1063984/s -42% -32% -20% -20% .
|
||||
#+end_example
|
||||
|
||||
* Références
|
||||
* [[https://github.com/jwbargsten/python-timethese][Github]]
|
32
20220429091956-ci_cd.org
Normal file
@@ -0,0 +1,32 @@
|
||||
:PROPERTIES:
|
||||
:ID: 607219f8-675b-4244-a3ce-b399bf210366
|
||||
:mtime: 20220429094502
|
||||
:ctime: 20220429091956
|
||||
:END:
|
||||
#+title: CI/CD
|
||||
|
||||
* Introduction
|
||||
* Comble le fossé entre les activités et les équipes de développement et d'exploitation en imposant :
|
||||
* L'automatisation de la création, des tests (CI),
|
||||
* Du déploiement des applications (CD).
|
||||
* Les pratiques DevOps modernes impliquent le CI/CD et la surveillance continue des applications logicielles tout au long de leur cycle de vie.
|
||||
|
||||
* CI (Continuous Integration)
|
||||
* Première étape du pipeline,
|
||||
* Intégration des modifications apportées au code par différents développeurs dans un dépôt (ie: Git),
|
||||
* Exécution de tests unitaires et d'intégration,
|
||||
* Couplé au process de développement [[id:6da0b985-e6f4-4454-bb6a-e941b722365b][Test driven development]].
|
||||
|
||||
* CD (Continuous Delivery/Continuous Deployment)
|
||||
** Continuous Delivery
|
||||
* Livraison manuelle du /build/ (dépose dans un app store par exemple),
|
||||
* Quand il est nécessaire de réaliser des tests manuels (/acceptance tests/) après le CI.
|
||||
** Continuous Deployment
|
||||
* Livraison automatique du code sortant du CI (résultats de test satisfaisants).
|
||||
* Permet une plus grande réactivité: livraison dès que le code est prêt (plus de livraison formelle),
|
||||
* Ajoute une pression sur l'équipe de développement,
|
||||
* Nécessite que les tests effectués en CI soient suffisants.
|
||||
|
||||
* Références
|
||||
* [[https://fr.wikipedia.org/wiki/CI/CD][Wikipedia]]
|
||||
* [[https://blog.devgenius.io/a-simple-definition-of-the-ci-cd-pipeline-8a48169be938?source=rss----4e2c1156667e---4][Definition of the CI/CD pipeline - Medium]]
|
54
20220429093533-test_driven_development.org
Normal file
@@ -0,0 +1,54 @@
|
||||
:PROPERTIES:
|
||||
:ID: 6da0b985-e6f4-4454-bb6a-e941b722365b
|
||||
:mtime: 20220429104331
|
||||
:ctime: 20220429093533
|
||||
:END:
|
||||
#+title: Test driven development
|
||||
|
||||
* Introduction
|
||||
* Initialement, cela consistait à écriture les tests avant de coder (/test-first design/),
|
||||
* Méthode de dev. logiciel consistant à concevoir un logiciel step by step en :
|
||||
* Ecrivant les tests avant la feature,
|
||||
* Remaniant le code continuellement.
|
||||
|
||||
* Les 3 lois du Test Driven Development
|
||||
|
||||
| N° | Lois | |
|
||||
|----+---------------------------------------------------------------------------------------------------------------------+---|
|
||||
| 1 | Il faut écrire un test qui échoue avant d’écrire le code de production correspondant. | |
|
||||
| 2 | Il faut écrire une seule assertion à la fois, qui fait échouer le test ou qui échoue à la compilation. | |
|
||||
| 3 | Il faut écrire le minimum de code de production pour que l'assertion du test actuellement en échec soit satisfaite. | |
|
||||
|
||||
* Processus cyclique de développement
|
||||
|
||||
#+DOWNLOADED: https://upload.wikimedia.org/wikipedia/commons/0/0e/Cycle-global-tdd.png @ 2022-04-29 10:17:43
|
||||
#+ATTR_ORG: :width 800
|
||||
[[file:Processus cyclique de développement/Cycle-global-tdd_2022-04-29_10-17-43.png]]
|
||||
|
||||
** Intérêts
|
||||
* Permet préciser le besoin, puis de spécifier le comportement souhaité, avant chaque étape de codage. Le logiciel
|
||||
produit répond avec justesse au besoin et est conçu pour le faire avec une complexité minimale => meilleures
|
||||
conception et testabilité, et logiciel plus fiable et de meilleure qualité.
|
||||
* Chaque test correspond à des modifications du code minimales : un test unique permet de faire un lien évident entre
|
||||
une régression et sa cause en cas d'échec.
|
||||
* Le rejeu des tests suite à la modification du code permet d'envisager avec sérénité n'importe quelle modification du
|
||||
code (transformation - modification qui affecte le comportement - ou d'un remaniement - modification qui n'altère pas le comportement).
|
||||
* Le remaniement régulier permet le réalignement de la conception du code avec les besoins connus, les tests permettant
|
||||
de garantir l'absence de régressions.
|
||||
* Les tests permettent aussi de documenter le comportement du logiciel.
|
||||
|
||||
Le TDD fait gagner en productivité de plusieurs façons, il permet de :
|
||||
* Eviter des modifications de code sans lien avec le but recherché (focalisation sur la satisfaction d'un besoin précis
|
||||
en conservant le cap du problème d'ensemble),
|
||||
* Eviter les accidents de parcours, où des tests échouent sans qu'on puisse identifier le changement à l'origine,
|
||||
* Maîtriser le coût des évolutions logicielles au fil du temps, grâce à une conception du code perméable au changement,
|
||||
* S'approprier plus facilement n'importe quelle partie du code en vue de le faire évoluer (chaque test ajouté explique et documente le comportement du logiciel en traduisant l'intention des auteurs),
|
||||
* Livrer une version d'un logiciel avec un haut niveau de confiance dans la qualité des livrables (couverture et pertinence des tests à sa construction).
|
||||
|
||||
** Programmation binomiale
|
||||
Différents usages:
|
||||
* Une personne écrit les tests, puis le code et une seconde supervise. Les rôles sont inversés régulièrement,
|
||||
* Une personne rédige les tests lorsque la seconde le code.
|
||||
|
||||
* Références
|
||||
* [[https://fr.wikipedia.org/wiki/Test_driven_development][Wikipedia]]
|
128
20220430122532-list_vs_tuple.org
Normal file
@@ -0,0 +1,128 @@
|
||||
:PROPERTIES:
|
||||
:ID: b9f392bd-bd45-4e9e-94ec-b19caedff86f
|
||||
:mtime: 20220501143116
|
||||
:ctime: 20220430122532
|
||||
:END:
|
||||
#+title: List vs tuple
|
||||
#+filetags: :Optimisation:Python:
|
||||
|
||||
* Points communs
|
||||
/list/ et /tuple/ sont des données de type /sequence/ :
|
||||
* L'ordre d'insertion des données est conservé (/ordered sets/),
|
||||
* Support des fonctions de concaténation, répétition, indexation et /slicing/,
|
||||
* Stockage de données hétérogèes (généralement homogènes)/
|
||||
|
||||
* Différences
|
||||
* Syntaxe ([] pour /list/, () pour /tuple/),
|
||||
* La /list/ est /mutable/, le /tuple/ /immutable/ (ne peut être modifié une fois créé),
|
||||
|
||||
** Empreinte RAM
|
||||
* Le /tuple/ requiert moins de RAM :
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
from sys import getsizeof
|
||||
from typing import List, Tuple
|
||||
|
||||
|
||||
def print_list_tuple_comparison(list_: List, tuple_: Tuple) -> None:
|
||||
list_size = getsizeof(list_)
|
||||
tuple_size = getsizeof(tuple_)
|
||||
diff = list_size - tuple_size
|
||||
print(f"Number of elements: {len(list_)}, list size: {list_size:<3}, tuple size: {tuple_size:<3}, diff: {diff} bytes ({diff/list_size*100:.2f}%)")
|
||||
|
||||
|
||||
def print_list_tuple_ram_footprint(elements_nb: int) -> None:
|
||||
list_ = []
|
||||
tuple_ = ()
|
||||
|
||||
print_list_tuple_comparison(list_, tuple_)
|
||||
|
||||
for i in range(1, elements_nb + 1):
|
||||
list_.append(i)
|
||||
tuple_ = tuple(range(1, i + 1))
|
||||
|
||||
print_list_tuple_comparison(list_, tuple_)
|
||||
|
||||
|
||||
print_list_tuple_ram_footprint(10)
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: Number of elements: 0, list size: 56 , tuple size: 40 , diff: 16 bytes (28.57%)
|
||||
: Number of elements: 1, list size: 88 , tuple size: 48 , diff: 40 bytes (45.45%)
|
||||
: Number of elements: 2, list size: 88 , tuple size: 56 , diff: 32 bytes (36.36%)
|
||||
: Number of elements: 3, list size: 88 , tuple size: 64 , diff: 24 bytes (27.27%)
|
||||
: Number of elements: 4, list size: 88 , tuple size: 72 , diff: 16 bytes (18.18%)
|
||||
: Number of elements: 5, list size: 120, tuple size: 80 , diff: 40 bytes (33.33%)
|
||||
: Number of elements: 6, list size: 120, tuple size: 88 , diff: 32 bytes (26.67%)
|
||||
: Number of elements: 7, list size: 120, tuple size: 96 , diff: 24 bytes (20.00%)
|
||||
: Number of elements: 8, list size: 120, tuple size: 104, diff: 16 bytes (13.33%)
|
||||
: Number of elements: 9, list size: 184, tuple size: 112, diff: 72 bytes (39.13%)
|
||||
: Number of elements: 10, list size: 184, tuple size: 120, diff: 64 bytes (34.78%)
|
||||
|
||||
** Temps de création
|
||||
Le /tuple/ est plus rapide à créé que la /list/:
|
||||
#+BEGIN_SRC python :results output
|
||||
from timeit import timeit
|
||||
|
||||
tuple_elapsed_time = timeit("(1,2,3,4,5,6,7,8,9,10)", number=10_000_000)
|
||||
list_elapsed_time = timeit("[1,2,3,4,5,6,7,8,9,10]", number=10_000_000)
|
||||
|
||||
print(f'Time needed to create a list of 10 ints 10_000_000 times: {list_elapsed_time}')
|
||||
print(f'Time needed to create a tuple of 10 ints 10_000_000 times: {tuple_elapsed_time} ({(list_elapsed_time - tuple_elapsed_time) / list_elapsed_time * 100:.2f}% faster)')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: Time needed to create a list of 10 ints 10_000_000 times: 0.6825288010004442
|
||||
: Time needed to create a tuple of 10 ints 10_000_000 times: 0.0716032920172438 (89.51% faster)
|
||||
|
||||
*** Création d'une liste et accès à un de ses membres
|
||||
#+BEGIN_SRC python :results output
|
||||
from dis import dis
|
||||
|
||||
def my_list():
|
||||
x = [10, 20, 30, 'abc']
|
||||
y = x[0]
|
||||
|
||||
dis(my_list)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: 4 0 LOAD_CONST 1 (10)
|
||||
: 2 LOAD_CONST 2 (20)
|
||||
: 4 LOAD_CONST 3 (30)
|
||||
: 6 LOAD_CONST 4 ('abc')
|
||||
: 8 BUILD_LIST 4
|
||||
: 10 STORE_FAST 0 (x)
|
||||
:
|
||||
: 5 12 LOAD_FAST 0 (x)
|
||||
: 14 LOAD_CONST 5 (0)
|
||||
: 16 BINARY_SUBSCR
|
||||
: 18 STORE_FAST 1 (y)
|
||||
: 20 LOAD_CONST 0 (None)
|
||||
: 22 RETURN_VALUE
|
||||
|
||||
*** Création d'un tuple et accès à un de ses membres
|
||||
#+BEGIN_SRC python :results output
|
||||
from dis import dis
|
||||
|
||||
def my_tuple():
|
||||
x = (10, 20, 30, 'abc')
|
||||
y = x[0]
|
||||
|
||||
dis(my_tuple)
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: 4 0 LOAD_CONST 1 ((10, 20, 30, 'abc'))
|
||||
: 2 STORE_FAST 0 (x)
|
||||
:
|
||||
: 5 4 LOAD_FAST 0 (x)
|
||||
: 6 LOAD_CONST 2 (0)
|
||||
: 8 BINARY_SUBSCR
|
||||
: 10 STORE_FAST 1 (y)
|
||||
: 12 LOAD_CONST 0 (None)
|
||||
: 14 RETURN_VALUE
|
||||
|
||||
La création d'un /tuple/ est plus rapide du fait de la [[id:26e1fdfb-1f8e-4c62-a08f-468a56ab03c8][Python peephole optimization]].
|
||||
|
||||
* Références
|
||||
* [[https://pub.towardsai.net/python-list-vs-tuple-an-in-depth-comparison-42c59348d8a8][Python List Vs. Tuple: An In-Depth Comparison - Medium]]
|
78
20220501130626-python_peephole_optimization.org
Normal file
@@ -0,0 +1,78 @@
|
||||
:PROPERTIES:
|
||||
:ID: 26e1fdfb-1f8e-4c62-a08f-468a56ab03c8
|
||||
:mtime: 20220501153548
|
||||
:ctime: 20220501130626
|
||||
:END:
|
||||
#+title: Peephole optimization
|
||||
|
||||
* Introduction
|
||||
Lorsque du code python est exécuté, celui-ci est compilé en /bytecode/ et enregistré dans des fichiers .pyc stockés dans
|
||||
les répertoires ~__pycache__~. Ces fichiers .pyc contiennent une version *optimisée* et plus *rapide* du code.
|
||||
|
||||
** L'objet /code/
|
||||
L'objet compilé /code/:
|
||||
* Est accessible depuis l'attribut ~__code__~ des fonctions,
|
||||
* Contient le *bytecode* et d'autres informations nécessaires à *CPython* pour son exécution, notamment :
|
||||
* ~co_consts~ : un tuple regroupant les constantes présentes dans la fonction,
|
||||
* ~co_varnames~ : un tuple regroupant le nom des variables locales utilisées par la fonction,
|
||||
* ~co_names~ : un tuple regroupant les noms non-locaux référencés dans le corps de la fonction.
|
||||
|
||||
* L'optimisation /Peephole/
|
||||
Durant la phase de *transcription* en bytecode, certaines données telles que les expressions numériques, /strings/ et /tuples/ sont optimisées et stockées dans des instruction *bytecode*.
|
||||
|
||||
** Les expressions constantes
|
||||
*** Les calculs numériques
|
||||
Les *expressions constantes* telles que ~a = 30 * 8 * 70~ sont optimisées.
|
||||
*** Les chaines de caractères et tuples
|
||||
Les *strings* dont la *longueur <= 4096* et les *tuples* dont la *longueur <= 256* sont optimisées, les autres, non.
|
||||
*** Les /membership tests/
|
||||
Les *membership tests* (opérateur ~in~ et ~not in~) permettent de tester la présence d'une valeur dans des
|
||||
/sequences/. Durant la phase de transcription, Python convertit les objets *mutables* (/list/ et /set/) en leur version *non mutables*:
|
||||
* Les *lists* en *tuples*,
|
||||
* Les *sets* en *frozen sets*
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
def toto():
|
||||
a = 30 * 8 * 7
|
||||
b = "TDS" * 3
|
||||
c = "T" * 4097
|
||||
d = (1, 2) * 5
|
||||
e = (10, ) * 257
|
||||
f = [101, 102] * 2
|
||||
print("Hello TDS !!!")
|
||||
|
||||
print(f'toto function constants: {toto.__code__.co_consts}')
|
||||
print(f'toto fonction local variable names: {toto.__code__.co_varnames}')
|
||||
print(f'toto fonction non-local names: {toto.__code__.co_names}')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: toto function constants: (None, 1680, 'TDSTDSTDS', 'T', 4097, (1, 2, 1, 2, 1, 2, 1, 2, 1, 2), (10,), 257, 101, 102, 2, 'Hello TDS !!!')
|
||||
: toto fonction local variable names: ('a', 'b', 'c', 'd', 'e', 'f')
|
||||
: toto fonction non-local names: ('print',)
|
||||
|
||||
Commentaires :
|
||||
* ~30 * 8 * 70~ est une *expression constante* et a été évaluée à ~16800~ par le compilateur,
|
||||
* ~“TDS” * 3~ est aussi une *expression constante* et sa *longueur est <= 4096*. Elle a été évaluée à
|
||||
~TDSTDSTDS~ par le compilateur,
|
||||
* ~“T” * 4097~, de *longueur > 4096*, n'est pas optimisée,
|
||||
* ~(1, 2) * 5~ est une séquence dont la *longueur est <= 256* (10). Elle a été évaluée et stockée comme le tuple ~(1,2,1,2,1,2,1,2,1,2)~.
|
||||
* ~(10,) * 257~ de *longueur > 256*, n'est pas optimisée,
|
||||
* ~[101, 102] * 2~ est une /list/ (objet *mutable*) et n'a pas été optimisée.
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
def toto():
|
||||
for a in [10, 20, 30]:
|
||||
pass
|
||||
|
||||
def titi():
|
||||
for a in {40, 50, 60}:
|
||||
pass
|
||||
|
||||
print(f'toto function constants: {toto.__code__.co_consts}')
|
||||
print(f'titi function constants: {titi.__code__.co_consts}')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: toto function constants: (None, (10, 20, 30))
|
||||
: titi function constants: (None, frozenset({40, 50, 60}))
|
64
20220501153651-interning_optimization.org
Normal file
@@ -0,0 +1,64 @@
|
||||
:PROPERTIES:
|
||||
:ID: c0d562c7-9d2f-4f35-b7b1-f6b6ca5273f9
|
||||
:mtime: 20220501162112
|
||||
:ctime: 20220501153651
|
||||
:END:
|
||||
#+title: Interning optimization
|
||||
|
||||
* Introduction
|
||||
* Concerne /CPython/,
|
||||
* Consiste en la *réutilisation* d'objet plutôt que d'en recrééer.
|
||||
|
||||
* Integer interning
|
||||
* Au démarrage, /CPython/ pré-charge en mémoire les entiers de *-5 à 256*,
|
||||
* A chaque fois qu'un entier compris dans cet intervalle est utilisé, celui-ci fait référence à un entier pré-chargé.
|
||||
#+BEGIN_SRC python :results output
|
||||
a = 100
|
||||
b = 100
|
||||
|
||||
print(f'Memory address of a: {id(a)}')
|
||||
print(f'Memory address of b: {id(b)}')
|
||||
print(f'a is b: {a is b}')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: Memory address of a: 9792128
|
||||
: Memory address of b: 9792128
|
||||
: a is b: True
|
||||
|
||||
* String interning
|
||||
* Au démarrage, /CPython/ pré-charge en mémoire les chaines de caractères présentes dans le code et de longueur *<=
|
||||
4096*,
|
||||
* Il est possible de forcer le pré-chargement en mémoire d'une chaine à l'aide de ~sys.intern~
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
from random import choice
|
||||
from string import printable
|
||||
from sys import intern
|
||||
|
||||
a = "Data"
|
||||
b = "Data"
|
||||
|
||||
print(f'Memory address of a: {id(a)}')
|
||||
print(f'Memory address of b: {id(b)}')
|
||||
print(f'a is b: {a is b}')
|
||||
|
||||
c = intern(''.join(choice(printable) for _ in range(4097)))
|
||||
d = c
|
||||
|
||||
print(f'Memory address of c: {id(c)}')
|
||||
print(f'Memory address of d: {id(d)}')
|
||||
print(f'c is d: {c is d}')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: Memory address of a: 139629084500336
|
||||
: Memory address of b: 139629084500336
|
||||
: a is b: True
|
||||
: Memory address of c: 28459264
|
||||
: Memory address of d: 28459264
|
||||
: c is d: True
|
||||
|
||||
* Références
|
||||
* [[https://pythonsimplified.com/optimization-in-python-interning/][Optimization in Python — Interning - pythonsimplified]]
|
||||
* [[https://stackoverflow.com/questions/55347581/why-does-the-is-operator-behave-differently-in-a-script-vs-the-repl][Why does the `is` operator behave differently in a script vs the REPL? - Stack-Overflow]]
|
117
20220501191904-git.org
Normal file
@@ -0,0 +1,117 @@
|
||||
:PROPERTIES:
|
||||
:ID: e93719b3-088d-4fe7-9ef8-fc9a4fd84827
|
||||
:mtime: 20221229111938
|
||||
:ctime: 20220501191904
|
||||
:END:
|
||||
#+title: Git
|
||||
|
||||
* Introduction
|
||||
* Outil de gestion de versions,
|
||||
* Créé par L. TORVALDS,
|
||||
* Fonctionnement décentralisé.
|
||||
|
||||
* Commandes
|
||||
| Commande | Action |
|
||||
|----------------+--------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ~git init~ | Crée un nouveau dépôt |
|
||||
| ~git clone~ | Clone un dépôt distant |
|
||||
| ~git add~ | Ajoute de nouveaux /blobs/ dans la base des objets pour chaque fichier modifié depuis le dernier commit. Les objets précédents restent inchangés |
|
||||
| ~git commit~ | Intègre la somme de contrôle SHA-1 d'un /tree/ et les sommes de contrôle des /commits/ parents pour créer un nouvel /commit/ |
|
||||
| ~git branch~ | Liste les branches |
|
||||
| ~git merge~ | Fusionne une branche dans une autre |
|
||||
| ~git rebase~ | Déplace les /commits/ de la branche courante devant les nouveaux /commits/ d’une autre branche |
|
||||
| ~git log~ | Affiche la liste des commits effectués sur une branche |
|
||||
| ~git push~ | Publie les nouvelles révisions sur le remote |
|
||||
| ~git pull~ | Récupère les dernières modifications distantes du projet (depuis le Remote) et les fusionne dans la branche courante |
|
||||
| ~git stash~ | Stocke de côté un état non commité afin d’effectuer d’autres tâches |
|
||||
| ~git checkout~ | Annule les modifications effectuées, déplacement sur une référence (branche, hash) |
|
||||
| ~git switch~ | Changement de branche |
|
||||
| ~git remote~ | Gestion des remotes |
|
||||
|
||||
Pour positionner ~HEAD~ :
|
||||
* Au commit père : ~git checkout HEAD^~ ou ~git checkout HEAD~1~,
|
||||
* En cas de plusieurs pères : ~git checkout HEAD^2~ pour positionner au second père,
|
||||
* Au commit grand-père : ~git checkout HEAD^^~ ou ~git checkout HEAD~2~
|
||||
|
||||
~HEAD~ est /detached/ lorsqu'un /checkout/ est effectué sur un /commit/ et non pas une /branch/.
|
||||
|
||||
Pour forcer le déplacement d'une branche : ~git branch -f <nom_branche> <commit>~.
|
||||
|
||||
Pour retourner en arrière :
|
||||
* Branche locale : ~git reset <commit>~ (position où nous souhaitons être).
|
||||
* Différentes options :
|
||||
* ~--soft~ : le commit sera supprimé mais les changements seront conservés et /stashed/,
|
||||
* ~--mixed~ (par défaut) : le commit sera supprimé mais les changements seront conservés et /unstashed/,
|
||||
* ~--hard <commit_ref>~ pour les changements à ne pas conserver.
|
||||
* Branche distante (/remote/) : ~git revert <commit_ref>~ :
|
||||
* Création d'un nouveau /commit/ qui inversera les modifications apportées par le ~<commit_ref>~,
|
||||
* Conservation de l'historique,
|
||||
* Pour supprimer plusieurs /commit/ consécutifs : ~git revert <older_ref>..<newer_ref>~ (~<older_ref>~~ exclu,
|
||||
~<newer_ref>~ inclus).
|
||||
|
||||
Pour copier une série de commits après l'emplacement actuel (/HEAD/) : ~git cherry-pick <commit_1> <commit_2> <...>~
|
||||
|
||||
*Rebase* interractif (~git rebase -i~) permet de :
|
||||
* Réarranger les /commits/,
|
||||
* Omettre certains /commits/ (/pick/),
|
||||
* Ecraser des /commits/.
|
||||
|
||||
Pour modifier le dernier commit : ~git commit --amend~.
|
||||
|
||||
Pour décrire (/describe/) les changements entre /HEAD/ et le tag le plus récent : ~git describe~ (~git describe <ref>~ sinon).
|
||||
|
||||
Pour mettre à jour une branche distante : ~git fetch~ :
|
||||
* Télécharge les /commits/ que le dépôt distant possède mais qui ne sont pas dans le notre, puis,
|
||||
* Met à jour nos branches distantes (par exemple, origin/main),
|
||||
* Ne met par à jour nos branches locales (par exemple, main),
|
||||
|
||||
Pour rapatrier (/fetch/) les branches distantes et les fusionner (/merge/) : ~git pull~.
|
||||
|
||||
Pour rapatrier (/fetch/) les branches distantes et /rebase/ : ~git pull --rebase~
|
||||
|
||||
Pour créer une branche afin que celle-ci suive une distante :
|
||||
* Création d'une nouvelle branche : ~git checkout -b <branche_locale> <branche_distante> ;git
|
||||
pull~,
|
||||
* La branche existe déjà : ~git branch -u <branche_distante> <branche_locale>~
|
||||
|
||||
** Correction
|
||||
Pour supprimer un fichier du dernier commit non /pushed/ : ~git reset --soft HEAD <filename>~.
|
||||
Pour commiter la correction d'un précédent /commit/ :
|
||||
#+BEGIN_SRC shell
|
||||
git commit --fixup <hash_commit_à_corriger>
|
||||
git rebase -i --autosquash
|
||||
#+END_SRC
|
||||
|
||||
** Comparaison
|
||||
Pour comparer deux branches : ~git diff <branche_a>..<branche_b>~.
|
||||
Pour comparer un fichier ou un répertoire entre deux branches : ~git diff <branche_a>..<branche_b> -- <path>~.
|
||||
Ajouter l'option ~-w~ à /git diff/ pour ignorer les espaces.
|
||||
|
||||
** Logs
|
||||
Pour afficher l'historique d'une fonction ou d'un fichier : ~git log -L:<class_name>:<filename>~
|
||||
Pour afficher les dernières positions de /HEAD/ : ~git reflog~.
|
||||
|
||||
* Outils tiers
|
||||
** Visualisation de dépôts
|
||||
*** [[https://github.com/rgburke/grv/][grv]]
|
||||
Visualisation de dépôts git depuis un terminal.
|
||||
*** [[https://github.com/o2sh/onefetch][onefetch]]
|
||||
Informations du dépôt courant au lancement d'un terminal.
|
||||
*** [[https://github.com/git-up/GitUp][GitUp]]
|
||||
Application de visualisation de dépôts pour MacOS.
|
||||
** Visualisation de différences
|
||||
*** [[https://github.com/dandavison/delta][Delta]]
|
||||
Affichage de ~git diff~.
|
||||
*** [[https://github.com/darrenburns/dunk][Dunk]]
|
||||
Affichage de ~git diff~.
|
||||
|
||||
* Apprentissage
|
||||
** [[https://github.com/benthayer/git-gud][Git-gud]]
|
||||
Jeu en ligne de commande permettant d'apprendre l'usage de Git.
|
||||
** [[https://learngitbranching.js.org/][learngitbranching.js.org]]
|
||||
Site permettant l'apprentissage de l'usage de Git.
|
||||
|
||||
* Références
|
||||
* [[https://martinheinz.dev/blog/43][Advanced Git features you didn't know You needed - Martin Heinz]]
|
||||
* [[https://medium.com/@porteneuve/getting-solid-at-git-rebase-vs-merge-4fa1a48c53aa][Getting solid at Git rebase vs. merge - Christophe Porteneuve]]
|
||||
* [[https://medium.com/@porteneuve/mastering-git-reset-commit-alchemy-ba3a83bdfddc][Mastering Git Reset: Commit Alchemy - Christophe Porteneuve]]
|
@@ -0,0 +1,52 @@
|
||||
:PROPERTIES:
|
||||
:ID: 20753ab5-70c3-4c8f-b261-56832cd5392c
|
||||
:mtime: 20220514132808
|
||||
:ctime: 20220514130004
|
||||
:END:
|
||||
#+title: Trouver le premier élément d'un iterable satisfaisant avec any
|
||||
|
||||
* Introduction
|
||||
|
||||
Le but est de remplacer le code suivant par une version plus courte à l'aide de la fonction /any/:
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
from timeit import timeit
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
def get_first_odd(items: List[int]) -> Optional[int]:
|
||||
for item in items:
|
||||
if item % 2:
|
||||
return item
|
||||
return None
|
||||
|
||||
count = 1_000_000
|
||||
elapsed = timeit(lambda: get_first_odd([14, 16, 18, 20, 35, 41, 100]), number=count)
|
||||
print(f'Elapsed time to find the first odd {count} times: {elapsed}.')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: Elapsed time to find the first odd 1000000 times: 0.31392509397119284.
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
from timeit import timeit
|
||||
from typing import List, Optional
|
||||
|
||||
def get_first_odd(items: List[int]) -> Optional[int]:
|
||||
is_odd = lambda x: x % 2
|
||||
if any(is_odd(found := item) for item in items):
|
||||
return found
|
||||
return None
|
||||
|
||||
count = 1_000_000
|
||||
elapsed = timeit(lambda: get_first_odd([14, 16, 18, 20, 35, 41, 100]), number=count)
|
||||
print(f'Elapsed time to find the first odd {count} times: {elapsed}.')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: Elapsed time to find the first odd 1000000 times: 0.9898421700345352.
|
||||
|
||||
|
||||
* Références
|
||||
* [[https://docs.python.org/fr/3/library/functions.html#any][Python Built-in Functions]]
|
||||
* [[https://mathspp.com/blog/pydonts/boolean-short-circuiting][Boolean short-circuiting - Pydon't]]
|
@@ -0,0 +1,45 @@
|
||||
:PROPERTIES:
|
||||
:ID: fa7e728b-dd2a-4d30-8f4b-e87813dc5f33
|
||||
:mtime: 20220514155841
|
||||
:ctime: 20220514133841
|
||||
:END:
|
||||
#+title: Modifier le style du texte affiché sur une console
|
||||
|
||||
* Introduction
|
||||
Le but est de modifier l'apparence de chaines de caractéres à afficher sur la console (/stdout/ ou /stderr/).
|
||||
|
||||
* Howto
|
||||
** Utilisation des [[https://stringfixer.com/fr/ANSI_escape_sequence][séquences d'échappement ANSI]]
|
||||
#+BEGIN_SRC python :results output
|
||||
BOLD_ESC = '\x1B[1m'
|
||||
UNDERLINED_ESC = '\x1B[4m'
|
||||
BOLD_AND_UNDERLINED_ESC = '\x1B[1;4m'
|
||||
CLOSING_ESC = '\x1B[0m'
|
||||
|
||||
def bold_and_uderline(text: str) -> str:
|
||||
return f'{BOLD_AND_UNDERLINED_ESC}{text}{CLOSING_ESC}'
|
||||
|
||||
text = "dummy text"
|
||||
print(f'{text} -> {bold_and_uderline(text)}')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: dummy text -> dummy text
|
||||
|
||||
** Utilisation du package [[https://github.com/hugovk/termcolor][termcolor]]
|
||||
#+BEGIN_SRC python :results output
|
||||
# Install: pip install termcolor
|
||||
from termcolor import colored
|
||||
|
||||
def bold_and_uderline(text: str) -> str:
|
||||
return colored(text, attrs=['bold', 'underline'])
|
||||
|
||||
text = "dummy text"
|
||||
print(f'{text} -> {bold_and_uderline(text)}')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: dummy text -> dummy text
|
||||
|
||||
* Références
|
||||
* [[https://github.com/hugovk/termcolor][termcolor - Github]]
|
38
20220516125736-difference_entre_les_operateurs_et.org
Normal file
@@ -0,0 +1,38 @@
|
||||
:PROPERTIES:
|
||||
:ID: 24408701-21d8-4f4e-aed9-c58746df2244
|
||||
:mtime: 20220516142825
|
||||
:ctime: 20220516125736
|
||||
:END:
|
||||
#+title: Différence entre les opérateurs + et +=
|
||||
|
||||
* Introduction
|
||||
Comment expliquer la différence de comportement entre les opérateurs *+* et *+=* :
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
a1 = a2 = [1, 2]
|
||||
a1 += [3] # Uses __iadd__, modifies a1 in-place
|
||||
print(f"When += is used: {a1=}, {a2=}")
|
||||
|
||||
a1 = a2 = [1, 2]
|
||||
a1.extend([3]) # Uses __add__, creates new list, assigns it to b1
|
||||
print(f"When extend is used: {a1=}, {a2=}")
|
||||
|
||||
a1 = a2 = [1, 2]
|
||||
a1 = a1 + [3] # Uses __add__, creates new list, assigns it to b1
|
||||
print(f"When + is used: {a1=}, {a2=}")
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: When += is used: a1=[1, 2, 3], a2=[1, 2, 3]
|
||||
: When extend is used: a1=[1, 2, 3], a2=[1, 2, 3]
|
||||
: When + is used: a1=[1, 2, 3], a2=[1, 2]
|
||||
|
||||
* Explications
|
||||
L'opérateur *+=* appelle la méthode dunder *__iadd__*. Si celle-ci n'existe pas (cas des objets /immutables/), il
|
||||
appelle *__add__*:
|
||||
* La méthode *__iadd__* signifie *in-place addition* : cela implique la modification de l'objet /mutable/ (et non la création
|
||||
d'une nouvelle instance - cf. __add__),
|
||||
* La méthode *__add__* retourne un nouvel object contenant le résultat de l'opération.
|
||||
|
||||
* Références
|
||||
* [[https://stackoverflow.com/questions/2347265/why-does-behave-unexpectedly-on-lists/2347423#2347423][Stackoverflow]]
|
47
20220516145022-type_object.org
Normal file
@@ -0,0 +1,47 @@
|
||||
:PROPERTIES:
|
||||
:ID: a32ab138-f9a8-4d61-9c09-97953c5a0a92
|
||||
:mtime: 20220516152042
|
||||
:ctime: 20220516145022
|
||||
:END:
|
||||
#+title: type == object
|
||||
|
||||
|
||||
* Introduction
|
||||
#+BEGIN_SRC python :results output
|
||||
from termcolor import colored
|
||||
|
||||
def check_instance(obj, type_):
|
||||
repr_attrs=['bold']
|
||||
ret = isinstance(obj, type_)
|
||||
print(f"Is {colored(obj.__name__, attrs=repr_attrs)} a instance of {colored(type_.__name__, attrs=repr_attrs)}: {ret}")
|
||||
return ret
|
||||
|
||||
for obj, type_ in [(type, object), (object, type), (object, object), (type, type)]:
|
||||
check_instance(obj, type_)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: Is type a instance of object: True
|
||||
: Is object a instance of type: True
|
||||
: Is object a instance of object: True
|
||||
: Is type a instance of type: True
|
||||
|
||||
* Explications
|
||||
* Tout est objet, ainsi ~isinstance(Anything, object)~ retourne toujours ~True~,
|
||||
* /type/ est une /metaclass/ permettant la construction de tous les types : int, str et object sont des instances du
|
||||
type /class/,
|
||||
* /type/ est le seul objet qui est une instance de lui même.
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
print(type(5))
|
||||
print(type(int))
|
||||
print(type(type))
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: <class 'int'>
|
||||
: <class 'type'>
|
||||
: <class 'type'>
|
||||
|
||||
* Références
|
||||
* [[https://medium.com/@saint_sdmn/10-hardest-python-questions-98986c8cd309][10 Hardest Python Questions - Medium]]
|
26
20220516151958-any_et_all_d_un_iterable_vide.org
Normal file
@@ -0,0 +1,26 @@
|
||||
:PROPERTIES:
|
||||
:ID: 16d16a4b-6a4c-4597-a45f-1a99f2cb9f29
|
||||
:mtime: 20220516154116
|
||||
:ctime: 20220516151958
|
||||
:END:
|
||||
#+title: Any et all d'un iterable vide
|
||||
|
||||
* Introduction
|
||||
#+BEGIN_SRC python :results output
|
||||
print(f"{any([])=}")
|
||||
print(f"{all([])=}")
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: any([])=False
|
||||
: all([])=True
|
||||
|
||||
* Explications
|
||||
* La fonction /build-in/ /any/ recherche le premier élément ~True~, et si aucun n'esst trouvé, retourne ~False~ (cas
|
||||
lorsque une /list/ est vide), sinon ~True~.
|
||||
* La fonction /build-in/ /all/ recherche le premier élément ~False~, et si aucun n'est trouvé, retourne ~True~, ~False~ sinon.
|
||||
|
||||
* Références
|
||||
* [[https://medium.com/@saint_sdmn/10-hardest-python-questions-98986c8cd309][10 Hardest Python Questions - Medium]]
|
||||
|
||||
|
31
20220516155011-ordre_de_resolution_des_attributs.org
Normal file
@@ -0,0 +1,31 @@
|
||||
:PROPERTIES:
|
||||
:ID: e9a0cb94-ee68-4dfd-9013-c83ce2a18481
|
||||
:mtime: 20220516155419
|
||||
:ctime: 20220516155011
|
||||
:END:
|
||||
#+title: Ordre de résolution des attributs
|
||||
|
||||
* Introduction
|
||||
#+BEGIN_SRC python :results output
|
||||
class A:
|
||||
answer = 42
|
||||
def __init__(self):
|
||||
self.answer = 21
|
||||
self.__add__ = lambda x, y: x.answer + y
|
||||
|
||||
def __add__(self, y):
|
||||
return self.answer - y
|
||||
|
||||
print(f"{A() + 5 = }")
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: A() + 5 = 16
|
||||
|
||||
* Explication
|
||||
Afin de résoudre les noms, Python cherche au niveau de l'instance, puis à celui de la classe et enfin à celui des
|
||||
classes parentes, sauf pour les /dunder methods/ pour lesquelles Python cherche directement au niveau de la classe.
|
||||
|
||||
* Référence
|
||||
* [[https://medium.com/@saint_sdmn/10-hardest-python-questions-98986c8cd309][10 Hardest Python Questions - Medium]]
|
||||
|
28
20220516155708-attribut_imag_des_types_numeriques.org
Normal file
@@ -0,0 +1,28 @@
|
||||
:PROPERTIES:
|
||||
:ID: 279b5e79-6918-432c-85fa-2fbefc06619a
|
||||
:mtime: 20220516160109
|
||||
:ctime: 20220516155708
|
||||
:END:
|
||||
#+title: Attribut imag des types numériques
|
||||
|
||||
* Introduction
|
||||
#+BEGIN_SRC python :results output
|
||||
ret = sum([
|
||||
el.imag
|
||||
for el in [
|
||||
0, 5, 10e9, float('inf'), float('nan')
|
||||
]
|
||||
])
|
||||
print(f"{ret =}")
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: ret =0.0
|
||||
|
||||
* Explication
|
||||
Le code précédent ne génère pas d'/AttributeError/ car tous les types numériques (/int/, /real/ et /float/) supportent
|
||||
les attributs /real/ (partie réelle) et /imag/ (partie imaginaire), /NaN/ et /Infinity/ inclus.
|
||||
|
||||
* Références
|
||||
* [[https://medium.com/@saint_sdmn/10-hardest-python-questions-98986c8cd309][10 Hardest Python Questions - Medium]]
|
||||
* [[https://docs.python.org/fr/3/library/numbers.html][Numbers - Classes de base abstraites numériques]]
|
33
20220516160421-evaluation_tardive.org
Normal file
@@ -0,0 +1,33 @@
|
||||
:PROPERTIES:
|
||||
:ID: 831fbfd2-c668-4099-b2d7-ecae734b9ec4
|
||||
:mtime: 20220519083124
|
||||
:ctime: 20220516160421
|
||||
:END:
|
||||
#+title: Evaluation tardive
|
||||
|
||||
* Introduction
|
||||
#+BEGIN_SRC python :results output
|
||||
class A:
|
||||
def function(self):
|
||||
return A()
|
||||
|
||||
a = A()
|
||||
A = int
|
||||
print(f"{a.function() = }")
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: a.function() = 0
|
||||
|
||||
* Explications
|
||||
* Le code contenu dans une fonction n'est exécuté uniquement lorsque celle-ci est invoquée. Ainsi, la référence à la
|
||||
fonction non déclarée ~A~ par la méthode ~A.function~ ne génère pas d'erreur,
|
||||
* Durant l'exécution de la méthode ~A.function~,
|
||||
|
||||
However, during the execution Python will bind the name A from
|
||||
the outer scope, which means that function method will return a newly created int instance.
|
||||
|
||||
|
||||
* Références
|
||||
* [[https://medium.com/@saint_sdmn/10-hardest-python-questions-98986c8cd309][10 Hardest Python Questions - Medium]]
|
||||
|
62
20220519082710-la_methode_new.org
Normal file
@@ -0,0 +1,62 @@
|
||||
:PROPERTIES:
|
||||
:ID: aaf77222-82d2-492c-bf5f-2dd47659b1be
|
||||
:mtime: 20220519210820
|
||||
:ctime: 20220519082710
|
||||
:END:
|
||||
#+title: La méthode __new__
|
||||
|
||||
* Synthaxe
|
||||
#+BEGIN_SRC python
|
||||
object.__new__(cls, *args, **kwargs)
|
||||
#+END_SRC
|
||||
La méthode ~object.__new__~ :
|
||||
* Crée les instances d'une classe (constructeur),
|
||||
* Est appelée avant ~object.__init__~,
|
||||
* Retourne une nouvelle instance ou une référence à une précedente (classes /singleton/).
|
||||
|
||||
* Exemples
|
||||
** Utilisation classique
|
||||
#+BEGIN_SRC python :results output
|
||||
class B:
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
print("__new__ running", cls, args, kwargs)
|
||||
return super().__new__(cls)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
print("__init__ running", self, args, kwargs)
|
||||
return super().__init__(*args, **kwargs)
|
||||
|
||||
for i in range(2):
|
||||
B()
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: __new__ running <class '__main__.B'> () {}
|
||||
: __init__ running <__main__.B object at 0x7f78f614c040> () {}
|
||||
: __new__ running <class '__main__.B'> () {}
|
||||
: __init__ running <__main__.B object at 0x7f78f614c040> () {}
|
||||
|
||||
** Singleton /design pattern/
|
||||
#+BEGIN_SRC python :results output
|
||||
class SingletonClass:
|
||||
|
||||
_instance = None
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
print("__new__ running", cls, args, kwargs)
|
||||
if cls._instance is None: # Checking if an instance of this class exists
|
||||
cls._instance = super().__new__(cls, *args, **kwargs) # Creating a new instace
|
||||
return cls._instance # Returing the instance
|
||||
|
||||
for i in range(2):
|
||||
print(f'{id(SingletonClass())=}')
|
||||
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: __new__ running <class '__main__.SingletonClass'> () {}
|
||||
: id(SingletonClass())=140699167274272
|
||||
: __new__ running <class '__main__.SingletonClass'> () {}
|
||||
: id(SingletonClass())=140699167274272
|
||||
|
||||
* Références
|
||||
* [[https://python.plainenglish.io/advanced-python-classes-objects-and-mro-423bb01521fb][Advanced Python classes objects and MRO - Medium]]
|
59
20220519090118-la_methode_prepare.org
Normal file
@@ -0,0 +1,59 @@
|
||||
:PROPERTIES:
|
||||
:ID: 0d9a7351-babd-4394-9d95-1d40cb46f615
|
||||
:mtime: 20220520230717
|
||||
:ctime: 20220519090118
|
||||
:END:
|
||||
#+title: La méthode __prepare__
|
||||
|
||||
* Synthaxe
|
||||
#+BEGIN_SRC python
|
||||
class.__prepare__()
|
||||
#+END_SRC
|
||||
La méthode ~class.__prepare__~ :
|
||||
* Cf. [[https://peps.python.org/pep-3115/][PEP-3115 - Metaclasses in Python 3000]],
|
||||
* Est utilisé comme /namespace/ local pour tout le code du corps de la
|
||||
classe (prépare le contenu du dictionnaire /__dict__/ de l'instance).
|
||||
* Est appelée avant ~class.__new__~,
|
||||
* Doit retourner un objet /dictionary-like/,
|
||||
|
||||
* Exemples
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
class DummyMeta(type):
|
||||
|
||||
@classmethod
|
||||
def __prepare__(mcs, name, bases, **kwargs):
|
||||
print('DummyMeta.__prepare__')
|
||||
return {'special': 1}
|
||||
|
||||
class Dummy(metaclass=DummyMeta):
|
||||
|
||||
def __new__(cls, name):
|
||||
print(f'Dummy.__new__({name})')
|
||||
return super().__new__(cls)
|
||||
|
||||
def __init__(self, name):
|
||||
super().__init__()
|
||||
self.name = name
|
||||
print(f'Dummy.__init__({self.name})')
|
||||
|
||||
dummy1, dummy2 = (Dummy(f'dummy{i + 1}') for i in range(2))
|
||||
print(f'{dummy1.special=}')
|
||||
dummy1.special += 1
|
||||
print(f'{dummy1.special=}')
|
||||
print(f'{dummy2.special=}')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: DummyMeta.__prepare__
|
||||
: Dummy.__new__(dummy1)
|
||||
: Dummy.__init__(dummy1)
|
||||
: Dummy.__new__(dummy2)
|
||||
: Dummy.__init__(dummy2)
|
||||
: dummy1.special=1
|
||||
: dummy1.special=2
|
||||
: dummy2.special=1
|
||||
|
||||
* Références
|
||||
* [[https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/][Understanding Python metaclasses - Ionel codelog]]
|
||||
* [[https://zestedesavoir.com/tutoriels/954/notions-de-python-avancees/4-classes/2-metaclasses/][Metaclasses - Zeste de savoir]]
|
89
20220520230639-la_methode_hash.org
Normal file
@@ -0,0 +1,89 @@
|
||||
:PROPERTIES:
|
||||
:ID: d1877b3b-3fe5-43d5-9be2-afb5ffe6b918
|
||||
:mtime: 20220522095337
|
||||
:ctime: 20220520230639
|
||||
:END:
|
||||
#+title: La méthode __hash__
|
||||
|
||||
* Synthaxe
|
||||
#+BEGIN_SRC python
|
||||
class.__hash__(self)
|
||||
#+END_SRC
|
||||
La méthode ~class.__hash__~ :
|
||||
* Est appelée par la /built-in method/ ~hash()~ et pour les opérations sur les membres des /hashed collection/ telles
|
||||
que /set/, /frozenset/ et /dict/,
|
||||
* Doit retourner un /int/,
|
||||
* Deux objet *égaux* doivent retourner la même valeur,
|
||||
* Si une classe *ne définit pas* de méthode ~__eq__~, elle ne doit pas définir de méthode ~__hash__~,
|
||||
* Si une classe *définit* une méthode ~__eq__~, mais pas de méthode ~__hash__~, ses instances :
|
||||
* Une méthode ~__hash__~ par défaut et retournant ~None~ est créée automatiquement,
|
||||
* Ne pourront pas être utilisées par les /hashable collections/,
|
||||
* Si une classe *définit* un objet /mutable/ et *définit* une méthode ~__eq__~, elle *ne doit pas* définir de méthode
|
||||
~__hash__~, l'implémentation des /hashables collections/ nécessitant que la valeur des clés soit /immutable/,
|
||||
* Par défaut, les classes définit par l'utilisateur possèdent les méthodes ~__eq__~ et ~__hash__~ (~id(obj) >> 4~):
|
||||
tous les objets sont comparés comme non-égaux (sauf chaque objet avec lui-même).
|
||||
|
||||
Si ~a == b~, alors ~hash(a) == hash(b)~.
|
||||
Si ~hash(a) == hash(b)~, alors ~a~ pourait être égal à ~b~.
|
||||
Si ~hash(a) != hash(b)~, alors ~a != b~.
|
||||
|
||||
* Exemples
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
from __future__ import annotations
|
||||
|
||||
print(f'{hash(10)=}')
|
||||
print(f'{hash("abc")=}')
|
||||
|
||||
class Dummy:
|
||||
|
||||
def __init__(self, first: str, second: str) -> None:
|
||||
self.first = first
|
||||
self.second = second
|
||||
|
||||
class HashableDummy:
|
||||
|
||||
def __init__(self, first: str, second: str) -> None:
|
||||
self.first = first
|
||||
self.second = second
|
||||
|
||||
def __eq__(self, other: HashableDummy) -> bool:
|
||||
return (other is not None
|
||||
and isinstance(other, HashableDummy)
|
||||
and self.first == other.first
|
||||
and self.second == other.second)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.first, self.second))
|
||||
|
||||
|
||||
dummy1, dummy2 = (Dummy("a", "b") for _ in range(2))
|
||||
print(f'{hash(dummy1)=}')
|
||||
print(f'{hash(dummy2)=}')
|
||||
print(f'{dummy1 == dummy2=}')
|
||||
|
||||
hashable_dummy1, hashable_dummy2 = (HashableDummy("a", "b") for _ in range(2))
|
||||
print(f'{hash(hashable_dummy1)=}')
|
||||
print(f'{hash(hashable_dummy2)=}')
|
||||
print(f'{repr(hashable_dummy1)=}')
|
||||
print(f'{repr(hashable_dummy2)=}')
|
||||
print(f'{hashable_dummy1 == hashable_dummy2=}')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: hash(10)=10
|
||||
: hash("abc")=-9106817633146148147
|
||||
: hash(dummy1)=8779192445928
|
||||
: hash(dummy2)=8779192413751
|
||||
: dummy1 == dummy2=False
|
||||
: hash(hashable_dummy1)=2529530665278513875
|
||||
: hash(hashable_dummy2)=2529530665278513875
|
||||
: repr(hashable_dummy1)='<__main__.HashableDummy object at 0x7fc10a69f4c0>'
|
||||
: repr(hashable_dummy2)='<__main__.HashableDummy object at 0x7fc10a51a1c0>'
|
||||
: hashable_dummy1 == hashable_dummy2=True
|
||||
|
||||
* Références
|
||||
* [[https://docs.python.org/3/reference/datamodel.html#object.__hash__][object.__hash__ - Docs Python]]
|
||||
* [[https://zestedesavoir.com/tutoriels/954/notions-de-python-avancees/1-starters/3-mutables-hashables/#3-3-hashables][Hashables - Zeste de savoir]]
|
||||
* [[https://eng.lyft.com/hashing-and-equality-in-python-2ea8c738fb9d][Hashing and equality in Python - Roy Williams]]
|
||||
|
66
20220522101323-method_resolution_order.org
Normal file
@@ -0,0 +1,66 @@
|
||||
:PROPERTIES:
|
||||
:ID: 1512a18b-221a-4f15-90a0-9ccac023dfd6
|
||||
:mtime: 20220528175444
|
||||
:ctime: 20220522101323
|
||||
:END:
|
||||
#+title: Method Resolution Order
|
||||
|
||||
* Introduction
|
||||
|
||||
Le /Method Resolution Order/ (MRO) est le mécanisme de recherche de méthodes et attributs dans les classes mères,
|
||||
notamment lors d'héritages multiples. Celui-ci est basé sur l'algorithme [[https://en.wikipedia.org/wiki/C3_linearization][C3 superclass linearization]].
|
||||
|
||||
* Ordres de résulution
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
class A:
|
||||
def func(self):
|
||||
print("B.func() called")
|
||||
|
||||
class B(A):
|
||||
def func(self):
|
||||
print("B.func() called")
|
||||
|
||||
class C(B, A):
|
||||
pass
|
||||
|
||||
c = C()
|
||||
c.func()
|
||||
print(f'{C.__mro__=}')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: B.func() called
|
||||
: C.__mro__=(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
|
||||
|
||||
Ordre : ~C -> B -> A -> object~ (pour un même niveau d'héritage, de gauche à droite).
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
class A:
|
||||
def func(self):
|
||||
print("A.func() called")
|
||||
|
||||
class B:
|
||||
def func(self):
|
||||
print("B.func() called")
|
||||
|
||||
class C(A, B):
|
||||
pass
|
||||
|
||||
class D(C, B):
|
||||
pass
|
||||
|
||||
d = D()
|
||||
d.func()
|
||||
print(f'{D.__mro__=}')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: A.func() called
|
||||
: D.__mro__=(<class '__main__.D'>, <class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
|
||||
|
||||
Ordre : ~D -> C -> A -> B -> object.~ (classe mères, de gauche à droite)
|
||||
|
||||
* Références
|
||||
* [[https://python.plainenglish.io/advanced-python-classes-objects-and-mro-423bb01521fb][Advanced Python classes objects and mro - Medium]]
|
||||
|
58
20220522143325-dataclasses.org
Normal file
@@ -0,0 +1,58 @@
|
||||
:PROPERTIES:
|
||||
:ID: f892dbdd-0cb5-4204-bca0-09aafb41f7ca
|
||||
:mtime: 20220522151003
|
||||
:ctime: 20220522143325
|
||||
:END:
|
||||
#+title: Dataclasses
|
||||
|
||||
* Introduction
|
||||
Le module /dataclasses/ :
|
||||
* Décrit par la [[https://www.python.org/dev/peps/pep-0557][PEP-557 - Data Classes]],
|
||||
* A été ajouté dans la version 3.7 de CPython,
|
||||
* Fournit un /decorator/ et des fonctions générant automatiquement des /dunder methods/, telles que ~__init__~ or
|
||||
~__repr__~, aux classes (évite l'écriture de /boilerplate code/).
|
||||
|
||||
* Howto
|
||||
** Dataclass /immutable/
|
||||
#+BEGIN_SRC python :results output
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from typing import List
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Tweets:
|
||||
""" Class to store tweets of users """
|
||||
|
||||
tweet_body: str = None
|
||||
tweet_time: datetime = datetime.utcnow()
|
||||
tweet_id: UUID = uuid4()
|
||||
tweet_lang: str = 'en-IN'
|
||||
tweet_place: str = 'IN'
|
||||
tweet_retweet_count: int = field(repr=False, compare=False, default=0)
|
||||
tweet_hashtags: List[str] = field(default_factory=list)
|
||||
tweet_user_id: str = None
|
||||
tweet_user_name: str = None
|
||||
|
||||
from inspect import getmembers, isfunction
|
||||
|
||||
for member in getmembers(Tweets, predicate=isfunction):
|
||||
print(member)
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: ('__delattr__', <function __create_fn__.<locals>.__delattr__ at 0x7ff1127a78b0>)
|
||||
: ('__eq__', <function __create_fn__.<locals>.__eq__ at 0x7ff1127a7790>)
|
||||
: ('__hash__', <function __create_fn__.<locals>.__hash__ at 0x7ff1127a7940>)
|
||||
: ('__init__', <function __create_fn__.<locals>.__init__ at 0x7ff1127a7550>)
|
||||
: ('__repr__', <function __create_fn__.<locals>.__repr__ at 0x7ff11287c670>)
|
||||
: ('__setattr__', <function __create_fn__.<locals>.__setattr__ at 0x7ff1127a7820>)
|
||||
|
||||
Il est nécessaire d'utiliser la méthode ~dataclasses.field~ et de préciser le paramètre ~default_factory~ pour l'utilisation d'objets /mutable/.
|
||||
|
||||
Les paramètres suivants de la méthode ~dataclasses.field~ permettent de contrôler le code généré :
|
||||
* ~repr~ : A mettre à ~False~ pour que l'attribut ne soit pas inclus dans la représentation (~__repr__~) de l'objet,
|
||||
* ~compare~: A mettre à ~False~ pour que l'attribut ne soit pas utilisé par la méthode ~__eq__~ de l'objet
|
||||
|
||||
* Références
|
||||
* [[https://medium.com/gitconnected/advanced-python-dataclasses-6a1e53bc4d8d][Advanced Python dataclasses - Medium]]
|
||||
* [[https://docs.python.org/3/library/dataclasses.html#dataclasses.dataclass][Dataclasses - Python]]
|
43
20220522151020-namedtuple.org
Normal file
@@ -0,0 +1,43 @@
|
||||
:PROPERTIES:
|
||||
:ID: 234f4590-b484-4286-9dbd-49612f4657be
|
||||
:mtime: 20220522171851
|
||||
:ctime: 20220522151020
|
||||
:END:
|
||||
#+title: NamedTuple
|
||||
|
||||
* Introduction
|
||||
Les /tuples/ sont des objets /immutables/ contenant des données /mutable/ ou non, homogènes ou non. Le contenu d'un
|
||||
/tuple/ est accessible depuis son index (cf. tableau). Le /namedtuple/ est un /tuple/ pour lequel le contenu est aussi
|
||||
accessible depuis un nom, rendant le code plus lisible.
|
||||
|
||||
Les /namedtuple/ prennent la même quantité de RAM que les /tuple/.
|
||||
|
||||
* Howto
|
||||
Le module /collections/ propose une implémentation de /namedtuple/ :
|
||||
#+BEGIN_SRC python :results output
|
||||
collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
from collections import namedtuple
|
||||
from sys import getsizeof
|
||||
|
||||
Point = namedtuple('Point', ['x', 'y'])
|
||||
p1 = Point(10, 20)
|
||||
|
||||
print(f'{p1=}')
|
||||
print(f'{p1.x == p1[0] = }')
|
||||
print(f'{p1.y == p1[1] = }')
|
||||
|
||||
print(f'{getsizeof(p1) == getsizeof((10, 20)) = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: p1=Point(x=10, y=20)
|
||||
: p1.x == p1[0] = True
|
||||
: p1.y == p1[1] = True
|
||||
: getsizeof(p1) == getsizeof((10, 20)) = True
|
||||
|
||||
* Références
|
||||
* [[https://pythonsimplified.com/what-are-namedtuples-in-python/][What are the named tuples in Python - Python Simplified]]
|
||||
* [[https://docs.python.org/3/library/collections.html#collections.namedtuple][Namedtuple - Python collections module]]
|
23
20220524120058-guix.org
Normal file
@@ -0,0 +1,23 @@
|
||||
:PROPERTIES:
|
||||
:ID: 393342ff-bf38-4472-8713-3de5ebe43eca
|
||||
:mtime: 20220526074246
|
||||
:ctime: 20220524120058
|
||||
:END:
|
||||
#+title: Guix
|
||||
|
||||
* Introduction
|
||||
Distribution du système GNU :
|
||||
* Constituée *exclusivement de logiciels libres*,
|
||||
* Gestionnaire de paquets : GNU *Guix*,
|
||||
* Gestionnaire de services : GNU *Shepherd*
|
||||
* Utilise le noyau *linux-libre*, prochainement *Hurd*.
|
||||
|
||||
* Configuration
|
||||
La configuration consiste en un ensemble de fichiers [[https://www.gnu.org/software/guile/][Guile Scheme]].
|
||||
|
||||
* Références
|
||||
* [[https://guix.gnu.org/][GNU Guix]]
|
||||
* [[https://www.gnu.org/software/shepherd/][GNU Shepherd]]
|
||||
** Configurations
|
||||
* [[https://github.com/podiki/dot.me/tree/master/guix/.config][Podiki's Guix config - Github]]
|
||||
* [[https://pad.lamyne.org/s/HJ5J3SWCN#][Guix : un outil pour les remplacer tous - Andréas Livet]]
|
10
20220524120307-moteurs_de_recherche.org
Normal file
@@ -0,0 +1,10 @@
|
||||
:PROPERTIES:
|
||||
:ID: 13205a76-7bbb-47c5-9176-f272ff65c1c0
|
||||
:mtime: 20220524120334
|
||||
:ctime: 20220524120307
|
||||
:END:
|
||||
#+title: Moteurs de recherche
|
||||
|
||||
* Payants
|
||||
* [[https://kagi.com/][Kagi]]
|
||||
|
71
20220525214257-drbd.org
Normal file
@@ -0,0 +1,71 @@
|
||||
:PROPERTIES:
|
||||
:ID: 34ceb92e-c507-4c61-9c6a-51501b80f054
|
||||
:mtime: 20220525221941
|
||||
:ctime: 20220525214257
|
||||
:END:
|
||||
#+title: DRBD
|
||||
|
||||
* Introduction
|
||||
DRBD :
|
||||
* *Distributed Replicated Block Device* en anglais, périphérique en mode bloc répliqué et distribué en français,
|
||||
* Architecture de stockage distribuée pour GNU/Linux,
|
||||
* Permet la réplication de périphériques de bloc (disques, partitions, volumes logiques etc.) entre des serveurs,
|
||||
* Open source et support commercial,
|
||||
* Est composé d'un module noyau et d'outils d'administration en /user space/,
|
||||
* peut être utilisé aussi bien en dessous qu'au-dessus de la pile de Linux LVM,
|
||||
* Support de la répartition de charge depuis la version 8,
|
||||
* Réplication entre 2 serveurs, plus à partir de la version 9.
|
||||
* Peut être intégré à un cluster ([[id:012e07b1-e12a-46e9-9a26-a93cde8b92ce][Pacemaker]] par exemple),
|
||||
* Est intégré au projet [[http://www.linux-ha.org/wiki/Main_Page][Linux HA]].
|
||||
|
||||
#+DOWNLOADED: https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/Drbd-arch.png/640px-Drbd-arch.png @ 2022-05-25 22:06:08
|
||||
#+ATTR_ORG: :width 500
|
||||
[[file:Introduction/640px-Drbd-arch_2022-05-25_22-06-08.png]]
|
||||
|
||||
* Réplication de données
|
||||
La réplication des données est réalisée :
|
||||
* En *temps réel* et *en permanence* : pendant que les applications modifient les données présentes sur le /block device/,
|
||||
* De façon *transparente* (réplication au niveau /block device/) : les applications n'ont pas conscience que ces
|
||||
données sont stockées et répliquées,
|
||||
* De façon synchrone ou asynchrone :
|
||||
* *Synchrone* : l'écriture sur le /block device/ entraine la mise à jour sur l'ensemble des serveurs avant la
|
||||
notification de fin d'écriture,
|
||||
* *Asynchrone* : la notification de fin d'écriture est réalisée avant la réplication de la données sur les autres
|
||||
serveurs.
|
||||
|
||||
* Principes de fonctionnement
|
||||
* DRBD ajoute une couche logique de /block device/ (conventionnellement nommée /dev/drbdX, ou X est le numéro de périph. mineur),
|
||||
* Les écritures sur le noeud primaire sont transférées sur le /block device/ et propagées au noeud secondaire pour que
|
||||
celui-ci transfère les données à son /block device/,
|
||||
* Les lectures sont effectées localement.
|
||||
|
||||
* En cas de défaillance du nœud primaire :
|
||||
* Un orchestrateur promeut le nœud /slave/ dans un état /master/,
|
||||
* Quand l'ancien nœud /master/, précédemment défaillant, revient, le système peut ou non l'élever au rôle de
|
||||
/master/, après une synchronisation des données du périphérique.
|
||||
* L'algorithme de synchronisation de DRBD est efficace : *seuls les blocs qui ont changé durant la panne doivent être
|
||||
resynchronisés*, plutôt que le périphérique dans son entièreté.
|
||||
|
||||
* Les outils
|
||||
** drbdadm
|
||||
Outil d'administration de haut niveau de DRBD. Il utilise le fichier de config ~/etc/drbd.conf~ et sert d'interface avec
|
||||
les outils suivants.
|
||||
*** Création d'une ressource (à faire sur chacun des serveurs)
|
||||
#+BEGIN_SRC shell :results output
|
||||
drbdadm create-md <resource>
|
||||
modprobe drbd
|
||||
drbdadm up <resource>
|
||||
#+END_SRC
|
||||
*** Pour forcer un serveur à passer /master/ (suite à un /split-brain/ par exemple)
|
||||
L'autre server devenant alors /slave/ et devant synchroniser ses données avec celles du nouveau maitre :
|
||||
#+BEGIN_SRC shell :results output
|
||||
drbdadm -- --overwrite-data-of-peer primary <resource>
|
||||
#+END_SRC
|
||||
** drbdsetup
|
||||
Outil du configuration du module DRBD après son chargement.
|
||||
** drbdmeta
|
||||
Outil permettant la manipulation des métadonnées des structures de DRBD.
|
||||
|
||||
* Références
|
||||
* [[https://fr.wikipedia.org/wiki/DRBD][Drbd - Wikipedia]]
|
||||
* [[https://fr-wiki.ikoula.com/fr/Mise_en_place_de_DRBD_en_mode_primaire-secondaire][Mise en place de DRBD en mode primaire/secondaire - wiki-ikoula]]
|
19
20220526073445-nyxt.org
Normal file
@@ -0,0 +1,19 @@
|
||||
:PROPERTIES:
|
||||
:ID: e7950306-e803-44a4-ae94-cc9cc7cf8191
|
||||
:mtime: 20220526075541
|
||||
:ctime: 20220526073445
|
||||
:END:
|
||||
#+title: Nyxt
|
||||
|
||||
* Introduction
|
||||
Navigateur web partageant les choix de conception d'Emacs :
|
||||
* Extensible (/lisp/),
|
||||
* Keyboard friendly.
|
||||
|
||||
* Références
|
||||
* [[https://nyxt.atlas.engineer/documentation][Documentation - Nyxt]]
|
||||
* [[https://github.com/ag91/emacs-with-nyxt][Some code to make Emacs interact with Nyxt - Github]]
|
||||
|
||||
** Configurations
|
||||
* [[https://github.com/aartaka/nyxt-config/tree/08c743e2a94ec63d432dc96002f7a9db025c5393][Aartaka Nyxt config - Github]]
|
||||
*
|
37
20220526082057-self_hosted_server.org
Normal file
@@ -0,0 +1,37 @@
|
||||
:PROPERTIES:
|
||||
:ID: 47707ab9-7792-4592-b25b-8dd2f2e45b05
|
||||
:mtime: 20221229104128
|
||||
:ctime: 20220526082057
|
||||
:END:
|
||||
#+title: Self-hosted server
|
||||
|
||||
* Introduction
|
||||
Consiste en l'hébergement soi-même d'un ensemble de services web.
|
||||
|
||||
* Gestion des certificats
|
||||
** Signature par un CA
|
||||
[[https://letsencrypt.org/][letsencrypt]] est utilisé pour signer les certificats générés pour les différentes interfaces.
|
||||
|
||||
Pour forcer le renouvellement du certificat (exemple du serveur de mail) :
|
||||
#+BEGIN_SRC shell
|
||||
certbot certonly --nginx --force-renew -d imap.adrien.run
|
||||
#+END_SRC
|
||||
|
||||
* Serveur git
|
||||
** [[id:bb755a02-0df1-4ee4-8b8c-3f36d8bdfff1][Gitea]]
|
||||
|
||||
* Mails
|
||||
** Serveur de mail
|
||||
*** [[id:c226d1ef-02e8-4cd5-bce6-e91a3843a291][Exim+dovecot]]
|
||||
** Webmail
|
||||
*** [[id:a9e9ba39-726e-4a49-876e-a0d58623cc48][Roundcube]]
|
||||
|
||||
* Vidéo
|
||||
** Plateforme de streaming
|
||||
*** [[https://github.com/Chocobozzz/PeerTube][PeerTube]]
|
||||
|
||||
* Rendez-vous (remplacement de Doodle)
|
||||
** [[id:8bb29bf5-219f-49ff-b410-e7cc2473337f][framadate]]
|
||||
|
||||
* Microblogging
|
||||
** [[id:056e86ae-99ad-45c6-be11-fe6582028870][mastodon]]
|
20
20220526082204-gitea.org
Normal file
@@ -0,0 +1,20 @@
|
||||
:PROPERTIES:
|
||||
:ID: bb755a02-0df1-4ee4-8b8c-3f36d8bdfff1
|
||||
:mtime: 20220526083212
|
||||
:ctime: 20220526082204
|
||||
:END:
|
||||
#+title: Gitea
|
||||
|
||||
* Introduction
|
||||
Solution légère d'hébergement de code (serveur git) :
|
||||
* Ecrite en Go,
|
||||
* Licence MIT.
|
||||
|
||||
* Installation
|
||||
Cf. [[https://linuxize.com/post/how-to-install-gitea-on-ubuntu-20-04/#installing-gitea][Installing Gitea]].
|
||||
|
||||
* Usage
|
||||
Cf. [[https://docs.gitea.io/en-us/][Docs - Gitea]].
|
||||
|
||||
* Références
|
||||
* [[https://gitea.io/en-us/][Gitea website]]
|
104
20220526083306-exim_dovecot.org
Normal file
@@ -0,0 +1,104 @@
|
||||
:PROPERTIES:
|
||||
:ID: c226d1ef-02e8-4cd5-bce6-e91a3843a291
|
||||
:mtime: 20220527114245
|
||||
:ctime: 20220526083306
|
||||
:END:
|
||||
#+title: Exim+dovecot
|
||||
|
||||
* Introduction
|
||||
La solution de serveur de mail est basée sur les OSS suivants :
|
||||
* [[https://www.exim.org/][Exim4]] : MTA léger (Serveur de mail SMTP),
|
||||
* [[https://www.dovecot.org/][Dovecot]] :
|
||||
* Serveur de mail POP/IMAP orienté sécurité,
|
||||
* gère les formats de boîte de messagerie [[https://fr.wikipedia.org/wiki/Mbox][mbox]] et [[https://fr.wikipedia.org/wiki/Maildir][maildir]].
|
||||
|
||||
* Les différents composants
|
||||
** Mail Transfer Agent (MTA)
|
||||
Composant en charge de :
|
||||
* La transmission des mail émis par ses utilisateurs vers un autre MTA,
|
||||
* L'acceptation des mails dont ses propres utilisateurs sont destinataires.
|
||||
Les MTA communiquent entre eux via le protocole SMTP.
|
||||
|
||||
** Mail Delivery Agent (MDA)
|
||||
Composant en charge de :
|
||||
* La réception des mails acceptés par le MTA,
|
||||
* Trie et dépose des mails reçus dans les boites de réception des utilisateurs.
|
||||
|
||||
** Mail Retrieval Agent (MRA)
|
||||
Composant collectant, depuis le poste de l'utilisateur, de ses mails hébergés par le serveur.
|
||||
|
||||
** Mail User Agent (MUA)
|
||||
Composant "IHM" :
|
||||
* Affichage des mails reçus,
|
||||
* Formattage des mails écrits.
|
||||
|
||||
** Mail Submission Agent (MSA)
|
||||
Composant relai entre le MUA et le MTA.
|
||||
|
||||
* Sécurisation
|
||||
** [[https://en.wikipedia.org/wiki/DomainKeys_Identified_Mail][DKIM]]
|
||||
DKIM :
|
||||
* Est un système de signature de mails en sortie de MTA,
|
||||
* La signature consiste en une clé publique disponible depuis le serveur DNS résolvant les noms associés au serveur,
|
||||
* Permet de garantir l'intégrité du message et certifier que l'émetteur du message dispose du couple clef privée/clef publique dont cette dernière est référencée sur le serveur DNS du domaine de courrier électronique.
|
||||
|
||||
* Installation
|
||||
** Exim4
|
||||
*** Fichier exim4.conf.template
|
||||
Modifier la section ~MAIN CONFIGURATION SETTINGS~ du fichier :
|
||||
#+BEGIN_SRC shell
|
||||
MAIN_TLS_ENABLE=true
|
||||
MAIN_TLS_CERTIFICATE=/etc/letsencrypt/live/smtp.adrien.run/fullchain.pem
|
||||
MAIN_TLS_PRIVATEKEY=/etc/letsencrypt/live/smtp.adrien.run/privkey.pem
|
||||
|
||||
DKIM_DOMAIN=adrien.run
|
||||
DKIM_SELECTOR=mail
|
||||
DKIM_PRIVATE_KEY=/etc/exim4/dkim.pem
|
||||
#+END_SRC
|
||||
*** Fichier update-exim4.conf.conf
|
||||
#+BEGIN_SRC shell
|
||||
cat >/etc/exim4/update-exim4.conf.conf <<EOF
|
||||
dc_eximconfig_configtype='internet'
|
||||
dc_other_hostnames='adrien.run;mail.adrien.run'
|
||||
dc_local_interfaces=''
|
||||
dc_readhost=''
|
||||
dc_relay_domains=''
|
||||
dc_minimaldns='false'
|
||||
dc_relay_nets='51.210.12.56' # Server IP
|
||||
dc_smarthost=''
|
||||
CFILEMODE='644'
|
||||
dc_use_split_config='false'
|
||||
dc_hide_mailname=''
|
||||
dc_mailname_in_oh='true'
|
||||
dc_localdelivery='maildir_home'
|
||||
EOF
|
||||
#+END_SRC
|
||||
|
||||
** Pour relancer automatiquement /dovecat/ après un renouvellement de certificat par /cerbot/
|
||||
#+BEGIN_SRC shell
|
||||
OUTPUT=/etc/letsencrypt/renewal-hooks/deploy/dovecat
|
||||
cat >${OUTPUT} <<EOF
|
||||
#!/bin/bash
|
||||
|
||||
for domain in $RENEWED_DOMAINS; do
|
||||
if [ "$domain" = imap.adrien.run ]; then
|
||||
doveadm reload >/dev/null
|
||||
fi
|
||||
done
|
||||
EOF
|
||||
chmod +x ${OUTPUT}
|
||||
#+END_SRC
|
||||
|
||||
Différents tutoriels utiles :
|
||||
* [[https://transang.me/setup-a-production-ready-exim-dovecot-server/][Setup a production-ready exim/dovecot server - Tran Sang]]
|
||||
* [[https://www.geekrant.org/2017/04/16/install-exim4-starttls-using-a-free-letsencrypt-certificate/][Install exim4 STARTTLS using a free LetsEncrypt certificate - Geekrant]]
|
||||
* [[https://buzut.net/connaitre-commandes-dompter-exim4/][Les commandes essentielles pour dompter Exim4 - Buzut]]
|
||||
|
||||
Le site [[https://mxtoolbox.com/SuperTool.aspx?action=smtp%3amail.adrien.run&run=toolpage][mxtoolbox]] permet de vérifier la configuration de serveurs de mail.
|
||||
|
||||
|
||||
* Références
|
||||
* [[https://medspx.fr/blog/Debian/exim4_beginner/][Solution de serveur de courrier électronique auto-hébergé (partie 2) : Débuter avec Exim4 sous Debian - Médéric Ribreux]]
|
||||
* [[https://medspx.fr/blog/Debian/exim4_beginner_part2/][Solution de serveur de courrier électronique auto-hébergé (partie 5) : Aller plus loin avec Exim4 sous Debian - Médéric Ribreux]]
|
||||
* [[https://medspx.fr/blog/Debian/mise_en_place_dkim_spf_dmarc_exim4_debian/][Mise en place de DKIM, SPF, DMARC sur Debian Jessie pour Exim4 - Médéric Ribreux]]
|
||||
*
|
92
20220526105643-roundcube.org
Normal file
@@ -0,0 +1,92 @@
|
||||
:PROPERTIES:
|
||||
:ID: a9e9ba39-726e-4a49-876e-a0d58623cc48
|
||||
:mtime: 20220527130858
|
||||
:ctime: 20220526105643
|
||||
:END:
|
||||
#+title: Roundcube
|
||||
|
||||
* Introduction
|
||||
|
||||
* Installation
|
||||
** Configuration de nginx
|
||||
# Configure nginx
|
||||
#+BEGIN_SRC shell
|
||||
cat >/etc/nginx/sites-available/mail <<EOF
|
||||
server {
|
||||
server_name mail.adrien.run;
|
||||
|
||||
access_log /var/log/nginx/mail.access.log;
|
||||
error_log /var/log/nginx/mail.error.log;
|
||||
|
||||
root /var/lib/roundcube;
|
||||
index index.php;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?q=$uri&$args;
|
||||
}
|
||||
|
||||
location ~ ^/(README.md|INSTALL|LICENSE|CHANGELOG|UPGRADING)$ {
|
||||
deny all;
|
||||
}
|
||||
|
||||
location ~ ^/(config|temp|logs)/ {
|
||||
deny all;
|
||||
}
|
||||
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
access_log off;
|
||||
log_not_found off;
|
||||
}
|
||||
|
||||
location ~ \.php$ {
|
||||
try_files $uri =404;
|
||||
fastcgi_pass unix:/var/run/php/php-fpm.sock;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000";
|
||||
|
||||
listen 443 ssl;
|
||||
}
|
||||
server {
|
||||
if ($host = mail.adrien.run) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
server_name mail.adrien.run;
|
||||
listen 80;
|
||||
return 404; # managed by Certbot
|
||||
}
|
||||
EOF
|
||||
ln -s /etc/nginx/sites-available/mail /etc/nginx/sites-enabled/mail
|
||||
certbot --nginx -d mail.adrien.run
|
||||
#+END_SRC
|
||||
** Installation et configuration
|
||||
#+BEGIN_SRC shell
|
||||
apt-get install roundcube roundcube-pgsql
|
||||
#+END_SRC
|
||||
Pour reconfigurer /roundcube/ :
|
||||
#+BEGIN_SRC shell
|
||||
dpkg-reconfigure roundcube-core
|
||||
#+END_SRC
|
||||
#+BEGIN_SRC shell
|
||||
cat >/etc/roundcube/debian-db.php <<EOF
|
||||
$dbuser='roundcube';
|
||||
$dbpass='<password>';
|
||||
$basepath='';
|
||||
$dbname='roundcubemail';
|
||||
$dbserver='localhost';
|
||||
$dbport='';
|
||||
$dbtype='pgsql';
|
||||
EOF
|
||||
#+END_SRC
|
||||
Modifier les lignes suivantes dans le fichier ~/etc/roundcube/config.inc.php~ :
|
||||
#+BEGIN_SRC php
|
||||
$config['default_host'] = array("tls://imap.adrien.run");
|
||||
$config['smtp_server'] = 'smtp.adrien.run';
|
||||
#+END_SRC
|
||||
|
||||
* Références
|
15
20220527131001-magit.org
Normal file
@@ -0,0 +1,15 @@
|
||||
:PROPERTIES:
|
||||
:ID: 22c81d3d-29cc-4b49-8e94-bf8a7f8cb9b9
|
||||
:mtime: 20220527131143
|
||||
:ctime: 20220527131001
|
||||
:END:
|
||||
#+title: Magit
|
||||
|
||||
* Introduction
|
||||
|
||||
* Howto
|
||||
** Comment faire un /rebase/ afin de modifier des précédents /commit/
|
||||
Cf. [[https://www.lvguowei.me/post/magit-rebase/][Magit rebase - Guowei Lv]]
|
||||
|
||||
* Références
|
||||
|
99
20220527165926-l_attribut_de_classe_slots.org
Normal file
@@ -0,0 +1,99 @@
|
||||
:PROPERTIES:
|
||||
:ID: 05864d6a-7a05-4c11-af14-4faebfdd1926
|
||||
:mtime: 20220527182207
|
||||
:ctime: 20220527165926
|
||||
:END:
|
||||
#+title: L'attribut de classe __slots__
|
||||
|
||||
* Introduction
|
||||
Par défaut, chaque objet possède l'attibut ~__dict__~ stockant la liste de ses attributs sous forme de ~dict~. Il est
|
||||
ainsi possible d'ajouter des attributs à un objet en dehors de la méthode ~__init__~ :
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
from sys import getsizeof
|
||||
|
||||
class Dummy:
|
||||
|
||||
def __init__(self, a: int, b: int) -> None:
|
||||
self.a = a
|
||||
self.b = b
|
||||
|
||||
dummy = Dummy(1, 2)
|
||||
try:
|
||||
print(dummy.__slots__)
|
||||
except AttributeError as e:
|
||||
print(e)
|
||||
|
||||
print(f'{dummy.__dict__=}')
|
||||
|
||||
dummy.c = 3
|
||||
print(f'{dummy.__dict__=}')
|
||||
|
||||
print(f'{getsizeof(dummy) + getsizeof(dummy.__dict__)}')
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: 'Dummy' object has no attribute '__slots__'
|
||||
: dummy.__dict__={'a': 1, 'b': 2}
|
||||
: dummy.__dict__={'a': 1, 'b': 2, 'c': 3}
|
||||
: 152
|
||||
|
||||
L'utilisation d'un ~dict~ pour stocker les attributs de chaque objet permet cette souplesse mais a pour conséquence un
|
||||
usage mémoire qui pourrait être amélioré.
|
||||
|
||||
C'est pour cela que l'attributs ~__slots__~ a été ajouté par Python3.
|
||||
|
||||
* Usage
|
||||
L'attribut de classe ~__slots__~ est un tuple (taille inférieure à celle d'un ~dict~ mais /imutable/) contenant les
|
||||
attributs des instances.
|
||||
#+BEGIN_SRC python :results output
|
||||
from sys import getsizeof
|
||||
|
||||
class Dummy:
|
||||
|
||||
__slots__ = ('a', 'b', 'c')
|
||||
|
||||
def __init__(self, a: int, b: int) -> None:
|
||||
self.a = a
|
||||
self.b = b
|
||||
|
||||
dummy = Dummy(1, 2)
|
||||
try:
|
||||
print(dummy.__dict__)
|
||||
except AttributeError as e:
|
||||
print(e)
|
||||
|
||||
print(f'{dummy.__slots__=}')
|
||||
|
||||
dummy.c = 3
|
||||
print(f'{dummy.__slots__=}')
|
||||
|
||||
try:
|
||||
dummy.d = 4
|
||||
except AttributeError as e:
|
||||
print(e)
|
||||
|
||||
print(f'{getsizeof(dummy) + getsizeof(dummy.__slots__)}')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: 'Dummy' object has no attribute '__dict__'
|
||||
: dummy.__slots__=('a', 'b', 'c')
|
||||
: dummy.__slots__=('a', 'b', 'c')
|
||||
: 'Dummy' object has no attribute 'd'
|
||||
: 120
|
||||
** Avantages
|
||||
L'usage de ~__slots__~ permet de réduire la taille des objets. Néanmoins, l'écart se réduit plus le nombre d'attributs
|
||||
augmente. Les ~__slots__~ sont donc utiles pour les classes ayant peu d'attributs et un grand nombre d'instances.
|
||||
|
||||
Le principal avantage de ~__slots__~ réside dans les performances (environ 15% plus rapide), conséquence du temps
|
||||
d'accès plus rapide au contenu d'un ~tuple~ que d'un ~__dict__~.
|
||||
** Inconvénients
|
||||
L'absence de ~__dict__~ empèche l'ajout dynamique d'attributs.
|
||||
|
||||
L'usage de ~__slots__~ ajoute les règles suivantes quant à l'héritage :
|
||||
* Les slots d’une classe mère s’ajoutent à ceux de la classe fille,
|
||||
* Il ne peut exister qu’une seule classe mère avec une séquence de slots non vide,
|
||||
* Si une des classes membres de l'arbre d'héritage ne déclare pas de ~__slots__~, mêmes vides, les instances auront un attribut ~__dict__~ (perte de l'optimisation).
|
||||
|
||||
* Références
|
||||
* [[https://www.invivoo.com/les-slots-une-optimisation-meconnue/][Les slots, une optimisation méconnue - Invivoo]]
|
55
20220527190024-fonction_zip.org
Normal file
@@ -0,0 +1,55 @@
|
||||
:PROPERTIES:
|
||||
:ID: acda43fa-70be-4939-9128-47114e48e4cb
|
||||
:mtime: 20220528183525
|
||||
:ctime: 20220527190024
|
||||
:END:
|
||||
#+title: Fonction zip
|
||||
|
||||
* Introduction
|
||||
Fonction /built-in/ permettant l'itération de plusieurs /iterable/ à la fois :
|
||||
* Si les /iterable/ n'ont pas le même nombre d'éléments, /zip/ arrêtera une fois le plus court atteint.
|
||||
|
||||
* Howto
|
||||
** /Iterable/ de tailles différentes
|
||||
#+BEGIN_SRC python :results output
|
||||
firsts = ["Anna", "Bob", "Charles", "Chris"]
|
||||
middles = ["Z.", "A.", "G."]
|
||||
lasts = ["Smith", "Doe", "Evans"]
|
||||
|
||||
for it in zip(firsts, middles, lasts):
|
||||
print(f'{type(it)=}')
|
||||
first, *others = it
|
||||
print(f"'{first} {others}'")
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: type(it)=<class 'tuple'>
|
||||
: 'Anna ['Z.', 'Smith']'
|
||||
: type(it)=<class 'tuple'>
|
||||
: 'Bob ['A.', 'Doe']'
|
||||
: type(it)=<class 'tuple'>
|
||||
: 'Charles ['G.', 'Evans']'
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
firsts = ["Anna", "Bob", "Charles", "Chris"]
|
||||
middles = ["Z.", "A.", "G."]
|
||||
lasts = ["Smith", "Doe", "Evans"]
|
||||
|
||||
for first, middle, last in zip(firsts, middles, lasts):
|
||||
print(f"'{first} {middle} {last}'")
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: 'Anna Z. Smith'
|
||||
: 'Bob A. Doe'
|
||||
: 'Charles G. Evans'
|
||||
|
||||
** Création d'un /dict/ avec /zip/
|
||||
#+BEGIN_SRC python :results output
|
||||
firsts = ["Anna", "Bob", "Charles"]
|
||||
lasts = ["Smith", "Doe", "Evans"]
|
||||
print(f'{dict(zip(firsts, lasts))=}')
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: dict(zip(firsts, lasts))={'Anna': 'Smith', 'Bob': 'Doe', 'Charles': 'Evans'}
|
||||
|
||||
* Références
|
||||
* [[https://mathspp.com/blog/pydonts/zip-up][Zip up - Pydon't]]
|
106
20220528104202-set_et_frozenset.org
Normal file
@@ -0,0 +1,106 @@
|
||||
:PROPERTIES:
|
||||
:ID: cc0e3fd0-2832-4bf6-909f-354507f7ed11
|
||||
:mtime: 20220528110155
|
||||
:ctime: 20220528104202
|
||||
:END:
|
||||
#+title: Set et frozenset
|
||||
|
||||
* /Set/
|
||||
Un /set/ est un ensemble /mutable/ et non ordonné d'éléments uniques.
|
||||
#+BEGIN_SRC python :results output
|
||||
groceries = {"milk", "cheese", "chocolate"}
|
||||
print(f'{groceries = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: groceries = {'milk', 'chocolate', 'cheese'}
|
||||
|
||||
** Egalité
|
||||
L'ordre n'a pas d'impact sur l'égalité entre deux /set/ :
|
||||
#+BEGIN_SRC python :results output
|
||||
groceries = {"milk", "cheese", "chocolate"}
|
||||
print(f'{set(["milk", "cheese", "chocolate"])==set(["chocolate", "milk", "cheese"]) = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: set(["milk", "cheese", "chocolate"])==set(["chocolate", "milk", "cheese"]) = True
|
||||
|
||||
** /Set comprehension/
|
||||
#+BEGIN_SRC python :results output
|
||||
veggies = ["broccoli", "carrot", "tomato", "pepper", "lettuce"]
|
||||
veggies_with_c = {veggie for veggie in veggies if "c" in veggie}
|
||||
|
||||
print(f'{veggies = }')
|
||||
print(f'{veggies_with_c = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: veggies = ['broccoli', 'carrot', 'tomato', 'pepper', 'lettuce']
|
||||
: veggies_with_c = {'carrot', 'lettuce', 'broccoli'}
|
||||
|
||||
** Opérations sur les /set/
|
||||
*** L'intersection entre des /set/ est réalisée avec l'opérateur ~&~
|
||||
#+BEGIN_SRC python :results output
|
||||
groceries = {"milk", "cheese", "chocolate"}
|
||||
treats = {"chocolate", "popcorn", "cookie"}
|
||||
|
||||
print(f'{groceries & treats = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: groceries & treats = {'chocolate'}
|
||||
|
||||
*** L'union entre des /set/ est réalisée avec l'opérateur ~|~
|
||||
#+BEGIN_SRC python :results output
|
||||
groceries = {"milk", "cheese", "chocolate"}
|
||||
treats = {"chocolate", "popcorn", "cookie"}
|
||||
|
||||
print(f'{groceries | treats = }')
|
||||
#+END_SRC
|
||||
|
||||
#+results:
|
||||
: groceries | treats = {'cheese', 'popcorn', 'chocolate', 'milk', 'cookie'}
|
||||
|
||||
*** La différences entre /set/ est réalisée avec l'opérateur ~-~
|
||||
#+BEGIN_SRC python :results output
|
||||
groceries = {"milk", "cheese", "chocolate"}
|
||||
treats = {"chocolate", "popcorn", "cookie"}
|
||||
|
||||
print(f'{groceries - treats = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: groceries - treats = {'milk', 'cheese'}
|
||||
|
||||
* /Frozenset/
|
||||
A l'inverse du /set/, le /frozenset/ est /immutable/ et est donc /hashable/ (utilisable comme clé des /dict/).
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
groceries = {"milk", "cheese", "chocolate"}
|
||||
frozen_groceries = frozenset(groceries)
|
||||
|
||||
try:
|
||||
frozen_groceries.add("beans")
|
||||
except AttributeError as e:
|
||||
print(e)
|
||||
|
||||
d = {}
|
||||
|
||||
try:
|
||||
d[groceries] = None
|
||||
except TypeError as e:
|
||||
print(e)
|
||||
|
||||
d[frozen_groceries] = None
|
||||
print(f'{d = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: 'frozenset' object has no attribute 'add'
|
||||
: unhashable type: 'set'
|
||||
: d = {frozenset({'chocolate', 'milk', 'cheese'}): None}
|
||||
|
||||
|
||||
|
||||
* Références
|
||||
* [[https://mathspp.com/blog/pydonts/set-and-frozenset][Set and frozenset - Pydon't]]
|
52
20220528110814-string.org
Normal file
@@ -0,0 +1,52 @@
|
||||
:PROPERTIES:
|
||||
:ID: 8b686fdd-2abd-459d-8d8d-0c57915de8fb
|
||||
:mtime: 20220528112853
|
||||
:ctime: 20220528110814
|
||||
:END:
|
||||
#+title: String
|
||||
|
||||
* Méthode /str.translate/
|
||||
La méthode /str.translate/ permet d'appliquer une table de substitution à la chaine de caractères :
|
||||
#+BEGIN_SRC python :results output
|
||||
translation_dict = {ord('a'): ord('A'), ord('b'): "BBB", ord('c'): None}
|
||||
print(f'{"aaa bbb ccc".translate(translation_dict) = }')
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: "aaa bbb ccc".translate(translation_dict) = 'AAA BBBBBBBBB '
|
||||
|
||||
* La méthode de classe /str.maketrans/
|
||||
La méthode de classe /str.maketrans/ simplifie la création des tables de translation utilisées par /str.stranslate/ en
|
||||
supprimant la nécessité d'utiliser la fonction ~ord~ :
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
# Without str.mktrans
|
||||
translation_dict = {ord("0"): "1", ord("1"): "0"}
|
||||
print(f'{"001011010101001".translate(translation_dict) = }')
|
||||
|
||||
# With str.maketrans (single argument)
|
||||
translation_dict = str.maketrans({'0': '1', '1': '0'})
|
||||
print(f'{"001011010101001".translate(translation_dict) = }')
|
||||
|
||||
# With str.maketrans (two arguments)
|
||||
translation_dict = str.maketrans("01", "10")
|
||||
print(f'{"001011010101001".translate(translation_dict) = }')
|
||||
print(f'{"#0F45cd".translate(str.maketrans("abcdef", "ABCDEF")) = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: "001011010101001".translate(translation_dict) = '110100101010110'
|
||||
: "001011010101001".translate(translation_dict) = '110100101010110'
|
||||
: "001011010101001".translate(translation_dict) = '110100101010110'
|
||||
: "#0F45cd".translate(str.maketrans("abcdef", "ABCDEF")) = '#0F45CD'
|
||||
|
||||
Le dernier argument de /str.maketrans/ permet de lister les caractères à remplacer par ~None~, à supprimer :
|
||||
#+BEGIN_SRC python :results output
|
||||
print(f'{"#0F45cd".translate(str.maketrans("abcdef", "ABCDEF", "#")) = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: "#0F45cd".translate(str.maketrans("abcdef", "ABCDEF", "#")) = '0F45CD'
|
||||
|
||||
* Références
|
||||
* [[https://mathspp.com/blog/pydonts/string-translate-and-maketrans-methods][String translate and maketrans methods - Pydon't]]
|
||||
|
56
20220528161514-la_methode_bool.org
Normal file
@@ -0,0 +1,56 @@
|
||||
:PROPERTIES:
|
||||
:ID: 5803422c-c089-4369-93cc-80caca71a26b
|
||||
:mtime: 20220528173751
|
||||
:ctime: 20220528161514
|
||||
:END:
|
||||
#+title: La méthode __bool__
|
||||
|
||||
* Synthaxe
|
||||
#+BEGIN_SRC python
|
||||
object.__bool__(self)
|
||||
#+END_SRC
|
||||
La méthode ~object.__bool__~ :
|
||||
* “Any object can be tested for truth value, for use in an if or while condition or as operand of the Boolean operations below [or, and and not].”,
|
||||
* Un objet est /Falsy/ lorsqu'il est /empty/ ou /without any useful value/,
|
||||
* Est appelée par la fonction /built-in/ /bool/.
|
||||
|
||||
* Exemples
|
||||
#+BEGIN_SRC python :results output
|
||||
print(f'{bool(None) = }')
|
||||
|
||||
print(f'{bool([]) = }')
|
||||
print(f'{bool([None]) = }')
|
||||
|
||||
print(f'{bool({}) = }')
|
||||
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: bool(None) = False
|
||||
: bool([]) = False
|
||||
: bool([None]) = True
|
||||
: bool({}) = False
|
||||
|
||||
* Par défaut, les instances de classes retournent /True/ :
|
||||
#+BEGIN_SRC python :results output
|
||||
class Dummy:
|
||||
pass
|
||||
|
||||
print(f'{bool(Dummy()) = }')
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: bool(Dummy()) = True
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
class Dummy:
|
||||
|
||||
def __bool__(self) -> bool:
|
||||
return False
|
||||
|
||||
print(f'{bool(Dummy()) = }')
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: bool(Dummy()) = False
|
||||
|
||||
* Références
|
||||
* [[https://mathspp.com/blog/pydonts/truthy-falsy-and-bool][Truthy falsy and bool - Pydon't]]
|
||||
|
30
20220528183301-fonction_vars.org
Normal file
@@ -0,0 +1,30 @@
|
||||
:PROPERTIES:
|
||||
:ID: 487f57f5-e9fc-4df7-ae14-b41f9c1fa186
|
||||
:mtime: 20220528184039
|
||||
:ctime: 20220528183301
|
||||
:END:
|
||||
#+title: Fonction vars
|
||||
|
||||
* Introduction
|
||||
Fonction /built-in/ retournant l'attribut ~__dict__~ d'un module, d'une classe, d'une instance ou de n'importe quel
|
||||
objet avec un attribut ~__dict__~.
|
||||
|
||||
* Howto
|
||||
#+BEGIN_SRC python :results output
|
||||
class Person:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
print(f'{vars(Person("me")) = }')
|
||||
|
||||
import math
|
||||
print(f'{vars(math) = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: vars(Person("me")) = {'name': 'me'}
|
||||
: vars(math) = {'__name__': 'math', '__doc__': 'This module provides access to the mathematical functions\ndefined by the C standard.', '__package__': '', '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': ModuleSpec(name='math', loader=<class '_frozen_importlib.BuiltinImporter'>, origin='built-in'), 'acos': <built-in function acos>, 'acosh': <built-in function acosh>, 'asin': <built-in function asin>, 'asinh': <built-in function asinh>, 'atan': <built-in function atan>, 'atan2': <built-in function atan2>, 'atanh': <built-in function atanh>, 'ceil': <built-in function ceil>, 'copysign': <built-in function copysign>, 'cos': <built-in function cos>, 'cosh': <built-in function cosh>, 'degrees': <built-in function degrees>, 'dist': <built-in function dist>, 'erf': <built-in function erf>, 'erfc': <built-in function erfc>, 'exp': <built-in function exp>, 'expm1': <built-in function expm1>, 'fabs': <built-in function fabs>, 'factorial': <built-in function factorial>, 'floor': <built-in function floor>, 'fmod': <built-in function fmod>, 'frexp': <built-in function frexp>, 'fsum': <built-in function fsum>, 'gamma': <built-in function gamma>, 'gcd': <built-in function gcd>, 'hypot': <built-in function hypot>, 'isclose': <built-in function isclose>, 'isfinite': <built-in function isfinite>, 'isinf': <built-in function isinf>, 'isnan': <built-in function isnan>, 'isqrt': <built-in function isqrt>, 'ldexp': <built-in function ldexp>, 'lgamma': <built-in function lgamma>, 'log': <built-in function log>, 'log1p': <built-in function log1p>, 'log10': <built-in function log10>, 'log2': <built-in function log2>, 'modf': <built-in function modf>, 'pow': <built-in function pow>, 'radians': <built-in function radians>, 'remainder': <built-in function remainder>, 'sin': <built-in function sin>, 'sinh': <built-in function sinh>, 'sqrt': <built-in function sqrt>, 'tan': <built-in function tan>, 'tanh': <built-in function tanh>, 'trunc': <built-in function trunc>, 'prod': <built-in function prod>, 'perm': <built-in function perm>, 'comb': <built-in function comb>, 'pi': 3.141592653589793, 'e': 2.718281828459045, 'tau': 6.283185307179586, 'inf': inf, 'nan': nan}
|
||||
|
||||
* Références
|
||||
* [[https://mathspp.com/blog/til/009][Vars - mathspp]]
|
||||
|
92
20220529102607-blockchain.org
Normal file
@@ -0,0 +1,92 @@
|
||||
:PROPERTIES:
|
||||
:ID: badea9d7-57cd-4734-98de-343f619ffe70
|
||||
:mtime: 20220529123703
|
||||
:ctime: 20220529102607
|
||||
:END:
|
||||
#+title: Blockchain
|
||||
|
||||
* Introduction
|
||||
Blockchain est une *technique de stockage de données* presque impossible à modifier, hacker ou manipuler les données
|
||||
stockées :
|
||||
* Basée sur la /Distributed Ledger Technology/ (DLT),
|
||||
* Principalement utilisée dans les domaines des cryptomonnaies et NFTs.
|
||||
|
||||
Il s'agit d'un *registre numérique de transactions* généralement partagé entre tous les noeuds du réseau. Celui-ci est
|
||||
composé d'une série de blocs incluant plusieurs transactions et à chaque fois qu'une nouvelle transaction est réalisée,
|
||||
un enregistrement de celle-ci est ajouté dans le registre de chaque participant.
|
||||
|
||||
Les données stockées dans la chaine de blocs est sécurisé par des signatures cryptographiques (hash des blocks respectifs).
|
||||
|
||||
* Les blocs
|
||||
Les blocs sont les éléments de base d'une /blockchain/ et sont constitués de :
|
||||
1) Transactions,
|
||||
2) Le /hash/ du précédent bloc,
|
||||
3) Le /hash/ de son propre contenu.
|
||||
|
||||
Le premier /block/ d'un chaine est appelé /genesis block/.
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
from rich import print
|
||||
from hashlib import sha256
|
||||
from json import dumps
|
||||
|
||||
def hash_string_256(string):
|
||||
"""Create a SHA256 hash for a given input string.
|
||||
Arguments:
|
||||
:string: The string which should be hashed.
|
||||
"""
|
||||
return sha256(string).hexdigest()
|
||||
|
||||
def hash_block(block):
|
||||
"""Hashes a block and returns a string representation of it.
|
||||
Arguments:
|
||||
:block: The block that should be hashed.
|
||||
"""
|
||||
return hash_string_256(dumps(block, sort_keys=True).encode())
|
||||
|
||||
genesis_block = {
|
||||
"previous_hash": "",
|
||||
"transactions": []
|
||||
}
|
||||
genesis_block_hash = hash_block(genesis_block)
|
||||
print(f'{genesis_block_hash = }')
|
||||
|
||||
block = {
|
||||
"previous_hash": genesis_block_hash,
|
||||
"index": 1,
|
||||
"transactions": [{"sender": "A", "receiver": "B", "amount": 0.5}],
|
||||
"proof": 9,
|
||||
}
|
||||
|
||||
block_hash = hash_block(block)
|
||||
print(f'{block_hash = }')
|
||||
|
||||
block['new_hash'] = block_hash
|
||||
print(f'{block = }')
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: genesis_block_hash =
|
||||
: '26cfa5c318d1195b72ecc139f11a740c5a71300dc1f3d4656188c684ac8ad01e'
|
||||
: block_hash = '25cdb202d88ccc0d1c3eae6d27af4c231e7e9f889885f1feb40c85128aac7c37'
|
||||
: block = {'previous_hash':
|
||||
: '26cfa5c318d1195b72ecc139f11a740c5a71300dc1f3d4656188c684ac8ad01e', 'index': 1,
|
||||
: 'transactions': [{'sender': 'A', 'receiver': 'B', 'amount': 0.5}], 'proof': 9,
|
||||
: 'new_hash': '25cdb202d88ccc0d1c3eae6d27af4c231e7e9f889885f1feb40c85128aac7c37'}
|
||||
|
||||
** /hash/
|
||||
Un /hash/ (sha256) est une /str/ de longueur fixe qui apporte une couche de chiffrement autour du /block/, rendant impossible la
|
||||
manipulation de la /blockchain/ (modification des transactions ou manipulation de la /blockchain/).
|
||||
|
||||
** /Proof of work/
|
||||
/Proof of work/ est un algorithme propre à une /blockchain/ :
|
||||
* C'est le mécanisme qui définit la difficulté à ajouter un /block/ à la /blockchain/,
|
||||
* Il s'agit d'un nombre devant satisfaire une condition en utilisant un /hash/, /hash/ différent des /hash/ contenu dans les /block/ existant,
|
||||
* Généralement, ce /hash/ est calculé ainsi : sha256((/transactions/ + /hash/ du /block/ précédent) + /proof of work/),
|
||||
* /Proof of work/ est ajouté aux /metadata/ du /block/ si le /hash/ calculé satisfait une ou plusieurs condition(s) arbitraire(s) (2
|
||||
premiers digits égaux à 0 par exemple), dans le cas échant /proof of work/ est incrémenté et le /hash/ recalculé
|
||||
jusqu'à satisfaction des conditions,
|
||||
|
||||
* Références
|
||||
* [[https://medium.com/@seaflux/getting-started-with-blockchain-and-programming-it-in-python-d7663b7cc3ef][Getting started with blockchain and programming it in python - Medium]]
|
||||
|
||||
|
138
20220529123824-generator.org
Normal file
@@ -0,0 +1,138 @@
|
||||
:PROPERTIES:
|
||||
:ID: 67410dad-d959-4029-b281-9bf1c9e69ede
|
||||
:mtime: 20220729213822
|
||||
:ctime: 20220529123824
|
||||
:END:
|
||||
#+title: Generator
|
||||
|
||||
* Introduction
|
||||
Un /generator/ est :
|
||||
* Une fonction retournant un /iterable/,
|
||||
* Un /iterable/ est un /object/ implémentant les méthodes ~__iter__~ et ~__next__~ et génère une erreur ~StopIteration~ lorsqu'il n'y a plus de valeur à retourner,
|
||||
* Utilise le /statement/ ~yield~ au lieu de ~return~.
|
||||
|
||||
Le statement ~return~ termine complètement une fonction alors que ~yield~ la suspend (sauvegarde de son contexte afin
|
||||
de continuer là où elle en était lors de son prochain appel).
|
||||
|
||||
Différences entre une /function/ et un /generator/ :
|
||||
* Présence d'au moins un ~yield~ dans un ~generator~,
|
||||
* Le /generator/ retourne un /iterator/ (les méthodes ~__iter__~ et ~__next__~ sont implémentées automatiquement),
|
||||
* Sauvegarde du contexte d'un /generator/,
|
||||
* L'erreur ~StopIteration~ est générée automatiquement lors qu'un /generator/ termine.
|
||||
|
||||
Les /generator/ sont appropriés quand il est nécessaire de produire un flux de données infini.
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
def simple_generator():
|
||||
for num in range(1, 4):
|
||||
print(num)
|
||||
yield num
|
||||
|
||||
gen = simple_generator()
|
||||
next(gen)
|
||||
next(gen)
|
||||
next(gen)
|
||||
try:
|
||||
next(gen)
|
||||
except StopIteration as __:
|
||||
print('StopIteration raised')
|
||||
|
||||
for num in simple_generator():
|
||||
pass
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: 1
|
||||
: 2
|
||||
: 3
|
||||
: StopIteration raised
|
||||
: 1
|
||||
: 2
|
||||
: 3
|
||||
|
||||
Un /generator/ peut être créé soit en déclarant une fonction (cf. exemple précédent) ou directement via une /generator
|
||||
expression/ :
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
list_numbers = [10, 18, 13, 23]
|
||||
list_square = [x**2 for x in list_numbers]
|
||||
|
||||
generator = (x**2 for x in list_numbers)
|
||||
|
||||
print(list_square)
|
||||
print(generator)
|
||||
#+END_SRC
|
||||
#+RESULTS:
|
||||
: [100, 324, 169, 529]
|
||||
: <generator object <genexpr> at 0x7fae7b90bb30>
|
||||
|
||||
* Différences avec /list/
|
||||
La principale différence entre les /list comprehension/ et les /generator expression/ consiste dans le fait que
|
||||
l'ensemble de la /list/ est créée par la /list compréhension/ alors que seul un /generator/ est produit par la
|
||||
/generator expression/. Cela apporte quelques avantages :
|
||||
* Chaque résultat du /generator/ n'est produit que suite à l'appel de ~__next__~ (/lazy execution/),
|
||||
* L'espace mémoire nécessaire s'en retrouve réduit,
|
||||
|
||||
Il peut s'avérer plus efficace d'utiliser un /generator/ lorsque l'ensemble des résultats ne sera pas utilisé à
|
||||
l'inverse pour les /list comprehension/.
|
||||
|
||||
* Enchainement de /generator/
|
||||
Il est possible d'enchainer plusieurs /generator/ :
|
||||
#+BEGIN_SRC python :results output
|
||||
def fibonacci_numbers(numbers):
|
||||
x, y = 0, 1
|
||||
for _ in range(numbers):
|
||||
x, y = y, x + y
|
||||
yield x
|
||||
|
||||
def square(numbers):
|
||||
for num in numbers:
|
||||
yield num**2
|
||||
|
||||
print(f'{sum(square(fibonacci_numbers(30))) = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: sum(square(fibonacci_numbers(30))) = 1120149658760
|
||||
|
||||
* Renvoyer une valeur à un /generator/
|
||||
#+BEGIN_SRC python :results output
|
||||
def dummy_generator():
|
||||
i = 0
|
||||
for i in range(10):
|
||||
print(f'from generator {yield i}')
|
||||
|
||||
generator = dummy_generator()
|
||||
received = generator.send(None)
|
||||
print(f'from here {received}')
|
||||
try:
|
||||
while True:
|
||||
received = generator.send(received + 100)
|
||||
print(f'from here {received}')
|
||||
except StopIteration:
|
||||
pass
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: from here 0
|
||||
: from generator 100
|
||||
: from here 1
|
||||
: from generator 101
|
||||
: from here 2
|
||||
: from generator 102
|
||||
: from here 3
|
||||
: from generator 103
|
||||
: from here 4
|
||||
: from generator 104
|
||||
: from here 5
|
||||
: from generator 105
|
||||
: from here 6
|
||||
: from generator 106
|
||||
: from here 7
|
||||
: from generator 107
|
||||
: from here 8
|
||||
: from generator 108
|
||||
: from here 9
|
||||
: from generator 109
|
||||
|
||||
* Références
|
||||
* [[https://blog.devgenius.io/what-is-generator-in-python-and-how-does-it-work-e6e0588785c3][What Is Generator in Python and How Does It Work ? - Medium]]
|
17
20220529131614-latex.org
Normal file
@@ -0,0 +1,17 @@
|
||||
:PROPERTIES:
|
||||
:ID: 3250943b-32f0-4bdc-b0d2-5fbcf1724f36
|
||||
:mtime: 20220529132210
|
||||
:ctime: 20220529131614
|
||||
:END:
|
||||
#+title: Latex
|
||||
|
||||
* Introduction
|
||||
LaTeX est :
|
||||
* Un language et un système de composition de documents,
|
||||
* Une collection de macro-commandes destinées à faciliter l'utilisation du « processeur de texte » TeX.
|
||||
|
||||
* Packages intéressants
|
||||
** [[https://ctan.crest.fr/tex-archive/macros/latex/contrib/fancyhdr/fancyhdr.pdf][Fancyhdr et extramarks]]
|
||||
Packages permettant de modifier le /layout/ d'un document.
|
||||
|
||||
* Références
|
52
20220530080115-youtube.org
Normal file
@@ -0,0 +1,52 @@
|
||||
:PROPERTIES:
|
||||
:ID: 8e30289a-0064-4803-ae64-2e1d8285dd3c
|
||||
:mtime: 20220530091227
|
||||
:ctime: 20220530080115
|
||||
:END:
|
||||
#+title: Youtube
|
||||
|
||||
* Introduction
|
||||
Est-ce nécessaire ?
|
||||
|
||||
* Obtenir l'id d'un /channel/ afin de s'abonner à son flux RSS
|
||||
#+BEGIN_SRC python :results output verbatim
|
||||
# pip install scrapy
|
||||
|
||||
from scrapy import Spider, Request
|
||||
from scrapy.crawler import CrawlerProcess
|
||||
from scrapy.utils.log import configure_logging
|
||||
|
||||
|
||||
class YoutubeChannelIdSpider(Spider):
|
||||
name = "youtube_channel"
|
||||
allowed_domains = ['youtube.com']
|
||||
|
||||
def __init__(self, channel, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.channel = channel
|
||||
self.url = f'https://www.youtube.com/c/{channel}'
|
||||
|
||||
def start_requests(self):
|
||||
yield Request(url=self.url, callback=self.parse, cookies={'CONSENT': 'YES+1'})
|
||||
|
||||
def parse(self, response):
|
||||
if channel_id := response.xpath('//meta[@itemprop="channelId"]/@content').get():
|
||||
print(f'{self.channel} channel ID is : "{channel_id}"')
|
||||
else:
|
||||
print(f'Unable to find ID for channel {self.channel}')
|
||||
|
||||
channel = input("What's the Youtube channel for which the ID shall be retrieved ?")
|
||||
|
||||
process = CrawlerProcess()
|
||||
process.crawl(YoutubeChannelIdSpider, channel=channel)
|
||||
process.start() # the script will block here until the crawling is finished
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: AAAAAAAAAAAAAAAAAAAAAAAAA
|
||||
: url = 'https://www.youtube.com/c/Matrixdotorg/'
|
||||
|
||||
* Références
|
||||
* [[https://docs.scrapy.org/en/latest/index.html][Docs - Scrapy]]
|
||||
* [[https://danielmiessler.com/blog/rss-feed-youtube-channel/][Rss feed youtube channel - Daniel Miessler]]
|
||||
* [[https://commentpicker.com/youtube-channel-id.php#youtube-channel-id][Comment Picker]]
|
69
20220604110059-json.org
Normal file
@@ -0,0 +1,69 @@
|
||||
:PROPERTIES:
|
||||
:ID: 6c59d844-1f1a-440c-be78-4a9df286fab6
|
||||
:mtime: 20220604114243
|
||||
:ctime: 20220604110059
|
||||
:END:
|
||||
#+title: Json
|
||||
|
||||
* Introduction
|
||||
*J*avaScript *O*bject *N*otation :
|
||||
* Est un format de données textuelles dérivé de la notation des objets du langage /JavaScript/,
|
||||
* Permet de représenter de l’information structurée,
|
||||
* A été créé par Douglas Crockford entre 2002 et 2005,
|
||||
* Première norme est ECMA-404, publiée en octobre 20032,
|
||||
* Actuellement décrit par les deux normes en concurrence : RFC 82593 de l’IETF et ECMA-4044 de l'ECMA, denière version
|
||||
publiée en décembre 2017.
|
||||
|
||||
* Spécifications
|
||||
Un document JSON comprend :
|
||||
* 2 types composés :
|
||||
* Objet ou dictionnaire (clés/valeurs),
|
||||
* Liste ordonnées de valeurs,
|
||||
* 4 types scalaires :
|
||||
* Booléen : /true/ ou /false/,
|
||||
* Nombre : décimal signé (pas de distinction entre entier et flottant),
|
||||
* Chaîne de caractères : séquence de 0 ou plusieurs caractères Unicode entourée de guillemets,
|
||||
* La valeur /null/ : une valeur vide.
|
||||
|
||||
* Extensions de JSON
|
||||
** JSON5
|
||||
Destiné à contourner les limitation de JSON :
|
||||
* Les noms des champs ne sont plus entre guillemets,
|
||||
* Ajout des commentaires (sur une ou plusieurs lignes),
|
||||
* Support du format hexadécimal pour les nombres,
|
||||
* Les nombres peuvent prendre les valeurs /Infinity/ ou /NaN/,
|
||||
* Espaces blancs supplémentaires autorisés,
|
||||
* Les /string/ peuvent être contenus entre apostrophes.
|
||||
** HJSON
|
||||
Destiné à contourner les limitation de JSON :
|
||||
* Les champs peuvent être séparés par un retour à la ligne au lieu d'une virgule,
|
||||
* Ajout des commentaires (sur une ou plusieurs lignes),
|
||||
* Utilisation des guillemets pour encapsuler une /string/ n'est pas obligatoire,
|
||||
* Les /string/ peuvent être écrites sur plusieurs lignes.
|
||||
|
||||
* Description d'une stucture de données JSON (JSPEC)
|
||||
JSPEC est un language décrivant une structure de données JSON (équivalent à xsd pour le xml).
|
||||
Les fichiers de descripion JSPEC ont l'extension /*.jspec/.
|
||||
|
||||
** Python
|
||||
Le module /[[https://github.com/chrismalcolm/jspec][jspec]]/ :
|
||||
#+BEGIN_SRC python :results output
|
||||
# pip install jspect
|
||||
from jspec import loads, check
|
||||
|
||||
spec = loads('{"name": string, "age": int, ... }')
|
||||
|
||||
chris = {"name": "Chris", "age": 26, "status": "online"}
|
||||
bob = {"name": "Bob", "age": 34.5}
|
||||
|
||||
print(f'{check(spec, chris) = }')
|
||||
print(f'{check(spec, bob) = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: check(spec, chris) = (True, '')
|
||||
: check(spec, bob) = (False, 'At location $ - exhausted JSON object, failed to match the following JSPEC pairs: ["age": int, ...]')
|
||||
|
||||
* Références
|
||||
* [[https://medium.com/@chrismalcolm_35838/the-best-json-validation-library-for-python-in-2022-b6de4f8014d4][The best json validation library for python in 2022 - Medium]]
|
||||
* [[https://fr.wikipedia.org/wiki/JavaScript_Object_Notation][Javascript Object Notation - Wikipedia]]
|
26
20220604134309-vale.org
Normal file
@@ -0,0 +1,26 @@
|
||||
:PROPERTIES:
|
||||
:ID: d2f9cefd-3e01-440a-a71b-b201edb3c619
|
||||
:mtime: 20220605213208
|
||||
:ctime: 20220604134309
|
||||
:END:
|
||||
#+title: Vale
|
||||
|
||||
* Introduction
|
||||
/Vale/ est un outil de vérification de texte 100% offline.
|
||||
|
||||
* Installation (ubuntu)
|
||||
#+BEGIN_SRC shell :results output
|
||||
CONFIG_ROOT=${HOME}
|
||||
|
||||
snap install vale --edge
|
||||
|
||||
# Téléchargement de la configuration
|
||||
cd "${CONFIG_ROOT}"
|
||||
git clone http://git.adrien.run/Adrien/vale-config.git
|
||||
#+END_SRC
|
||||
|
||||
** Intégration avec Emacs
|
||||
Patch de /flycheck-vale/ afin de gérer le chemin vers le fichier de configuration de /vale/ : [[https://git.adrien.run/Adrien/flycheck-vale][flycheck-vale]]
|
||||
|
||||
* Références
|
||||
* [[https://vale.sh/][Vale.sh]]
|
14
20220606212652-anki.org
Normal file
@@ -0,0 +1,14 @@
|
||||
:PROPERTIES:
|
||||
:ID: 247b0751-90e4-4832-aa15-68a182d93476
|
||||
:mtime: 20220606213432
|
||||
:ctime: 20220606212652
|
||||
:END:
|
||||
#+title: Anki
|
||||
|
||||
* Introduction
|
||||
|
||||
* Références
|
||||
** Emacs
|
||||
* [[https://github.com/louietan/anki-editor][Anki-editor - Github]]
|
||||
* [[https://rgoswami.me/posts/anki-decks-orgmode/][Anki Decks with Orgmode - Rohit Goswami]]
|
||||
* [[https://yiufung.net/post/anki-org/][Power up Anki with Emacs, Org mode, anki-editor and more - Cheong Yiufung]]
|
72
20220607074003-functools_singledispatch.org
Normal file
@@ -0,0 +1,72 @@
|
||||
:PROPERTIES:
|
||||
:ID: 25d994fd-375b-429d-af38-6afba818159f
|
||||
:mtime: 20220607075600
|
||||
:ctime: 20220607074003
|
||||
:END:
|
||||
#+title: functools.singledispatch
|
||||
|
||||
* Introduction
|
||||
Le module /functools/ permet la définition de /single dispatch methods/ :
|
||||
* Une sorte de méthode générique pour laquelle différentes implémentations sont écrites,
|
||||
* L'implémentation à exécuter est déterminée d'après le type du premier argument non /self/ ou non /cls/,
|
||||
* Peut être imbriqué (/nested/) avec d'autres décorateurs mais /singledispatchmethod/ doit être le plus englobant (cf. howto),
|
||||
* Depuis Python3.8 (3.9 pour les imbrications, cf. PCR 83860 en référence).
|
||||
|
||||
* Howto
|
||||
** Usage de base
|
||||
#+BEGIN_SRC python :results output
|
||||
from functools import singledispatchmethod
|
||||
|
||||
class Negator:
|
||||
|
||||
@singledispatchmethod
|
||||
def neg(self, arg):
|
||||
raise NotImplementedError("Cannot negate a")
|
||||
|
||||
@neg.register
|
||||
def _(self, arg: int):
|
||||
return -arg
|
||||
|
||||
@neg.register
|
||||
def _(self, arg: bool):
|
||||
return not arg
|
||||
|
||||
negator = Negator()
|
||||
print(f'{negator.neg(5) = }')
|
||||
print(f'{negator.neg(False) = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: negator.neg(5) = -5
|
||||
: negator.neg(False) = True
|
||||
** Imbrication (/nested/) avec d'autres /decorator/
|
||||
#+BEGIN_SRC python :results output
|
||||
from functools import singledispatchmethod
|
||||
|
||||
class Negator:
|
||||
|
||||
@singledispatchmethod
|
||||
@classmethod
|
||||
def neg(cls, arg):
|
||||
raise NotImplementedError("Cannot negate a")
|
||||
|
||||
@neg.register
|
||||
@classmethod
|
||||
def _(cls, arg: int):
|
||||
return -arg
|
||||
|
||||
@neg.register
|
||||
@classmethod
|
||||
def _(cls, arg: bool):
|
||||
return not arg
|
||||
|
||||
print(f'{Negator.neg(5) = }')
|
||||
print(f'{Negator.neg(False) = }')
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
|
||||
* Références
|
||||
* [[https://medium.com/@sunilrana123/python-trick-functools-singledispatch-4cdf71843cd2][Python Trick : functools.singledispatch - Medium]]
|
||||
* [[https://docs.python.org/3/library/functools.html#functools.singledispatchmethod][functools.singledispatch - Python]]
|
||||
* [[https://github.com/python/cpython/issues/83860][functools: singledispatchmethod doesn't work with classmethod #83860 - CPython Github]]
|
23
20220820195639-poetry.org
Normal file
@@ -0,0 +1,23 @@
|
||||
:PROPERTIES:
|
||||
:ID: 01f24d29-e833-4bfa-acb0-95140800d081
|
||||
:mtime: 20220820200208
|
||||
:ctime: 20220820195639
|
||||
:END:
|
||||
#+title: poetry
|
||||
|
||||
* Introduction
|
||||
* Utilitaire de gestion de projets Python (équivalent à ~yarn~).
|
||||
* Encapsule différents services:
|
||||
* ~venv~
|
||||
|
||||
* Configuration
|
||||
** Création des environnements virtuels dans le répertoire du projet
|
||||
#+BEGIN_SRC shell
|
||||
poetry config virtualenvs.in-project true
|
||||
#+END_SRC
|
||||
** Supprimer un cache
|
||||
#+BEGIN_SRC shell
|
||||
# Pour afficher la liste des environnements existants
|
||||
poetry env list
|
||||
poetry env remove <env_name>
|
||||
#+END_SRC
|
12
20220825074527-javascript.org
Normal file
@@ -0,0 +1,12 @@
|
||||
:PROPERTIES:
|
||||
:ID: d4197090-4ee5-4fa3-ba2d-a70ce9953923
|
||||
:mtime: 20220825074959
|
||||
:ctime: 20220825074527
|
||||
:END:
|
||||
#+title: Javascript
|
||||
|
||||
* Introduction
|
||||
Language interprété très largement utilisé pour les clients web. Il est aussi utilisé pour des applications backend ou
|
||||
standalone via /v8/ ou [[https://deno.land/][Deno]].
|
||||
|
||||
* Références
|
14
20220825080435-diffsitter.org
Normal file
@@ -0,0 +1,14 @@
|
||||
:PROPERTIES:
|
||||
:ID: 67317dba-3771-405f-ae58-0ef13062975d
|
||||
:mtime: 20220825080750
|
||||
:ctime: 20220825080435
|
||||
:END:
|
||||
#+title: diffsitter
|
||||
#+filetags: :TO_TRY:
|
||||
|
||||
* Introduction
|
||||
Outil de diff basé sur l'analyse d'arbres AST plutôt que de chaines de caractères pour identifier les différences entre
|
||||
deux fichiers contenant du code.
|
||||
|
||||
* Références
|
||||
* [[https://github.com/afnanenayet/diffsitter][GitHub - afnanenayet/diffsitter: A tree-sitter based AST difftool to get meaningful semantic diffs]]
|
13
20220825081058-batcat.org
Normal file
@@ -0,0 +1,13 @@
|
||||
:PROPERTIES:
|
||||
:ID: d5b19724-9559-44de-aef7-c4d57fb6dc95
|
||||
:mtime: 20230521174952
|
||||
:ctime: 20220825081058
|
||||
:END:
|
||||
#+title: batcat
|
||||
|
||||
* Introduction
|
||||
utilitaire permettant de visualiser les fichiers depuis un terminal avec une mise en forme plus évoluée que /cat/
|
||||
(coloration syntaxique).
|
||||
|
||||
* Références
|
||||
* [[https://github.com/sharkdp/bat][GitHub - sharkdp/bat: A cat(1) clone with wings.]]
|
31
20220830224237-fail2ban.org
Normal file
@@ -0,0 +1,31 @@
|
||||
:PROPERTIES:
|
||||
:ID: 00b1b480-0f0c-42a3-8952-4275bc10bc00
|
||||
:mtime: 20220831211359
|
||||
:ctime: 20220830224237
|
||||
:END:
|
||||
#+title: fail2ban
|
||||
|
||||
* Introduction
|
||||
Outil permettant de bloquer pendant une certaine durée toute IP depuis laquelle plusieurs tentatives de connexions ont
|
||||
échoué.
|
||||
|
||||
* Installation
|
||||
#+BEGIN_SRC shell
|
||||
apt install fail2ban
|
||||
#+END_SRC
|
||||
|
||||
* Configuration
|
||||
#+BEGIN_SRC shell
|
||||
cat >/etc/fail2ban/jail.d/sshd.local EOF<<
|
||||
[sshd]
|
||||
enabled = true
|
||||
port = ssh
|
||||
action = iptables-multiport
|
||||
logpath = /var/log/secure
|
||||
maxretry = 3
|
||||
bantime = 600
|
||||
EOF
|
||||
#+END_SRC
|
||||
|
||||
* Références
|
||||
* [[https://www.redhat.com/sysadmin/protect-systems-fail2ban][Linux security: Protect your systems with fail2ban - Redhat]]
|
328
20220908193040-solid.org
Normal file
@@ -0,0 +1,328 @@
|
||||
:PROPERTIES:
|
||||
:ID: b827c6e7-fe86-4301-a72c-dfaee85e142f
|
||||
:mtime: 20220910133550
|
||||
:ctime: 20220908193040
|
||||
:END:
|
||||
#+title: SOLID
|
||||
|
||||
* Introduction
|
||||
* Cinq principes de design de classes (P.O.O),
|
||||
* Principes décrits par Robert J. Martin (a.k.a Uncle Bob) en 2000,
|
||||
* Acronyme créé par Michael Feathers.
|
||||
|
||||
* Principes
|
||||
** Responsabilité unique (Single responsability principle)
|
||||
/A class should have one and only one reason to change, meaning that a class should have only one job./
|
||||
|
||||
Exemple de classe réalisant différentes tâches:
|
||||
* Calcul du total de la facture (méthode ~calculate_total~),
|
||||
* Impression de la facture (méthode ~print_invoice~),
|
||||
* Sauvegarde de la facture (méthode ~save_to_file~).
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
class Invoice:
|
||||
|
||||
def __init__(self, book, quantity, discount_rate, tax_rate, total):
|
||||
self.book = book
|
||||
self.quantity = quantity
|
||||
self.discount_rate = discount_rate
|
||||
self.tax_rate = tax_rate
|
||||
self.total = self.calculate_total()
|
||||
|
||||
def calculate_total(self):
|
||||
price = (self.book.price - self.book.price * self.discount_rate) * self.quantity
|
||||
price_with_taxe = price * (1 + self.tax_rate)
|
||||
return price_with_taxe
|
||||
|
||||
def print_invoice(self):
|
||||
print(f'{self.quantity}x {self.name} {self.price} $')
|
||||
print(f'Discount Rate: {self.discount_rate}')
|
||||
print(f'Tax Rate: {self.tax_rate}')
|
||||
print(f'Total: {self.total}')
|
||||
|
||||
def save_to_file(self):
|
||||
# Creates a file with given name and writes the invoice
|
||||
...
|
||||
#+END_SRC
|
||||
|
||||
Les erreurs :
|
||||
* La logique d'impression d'une facture (méthode ~print_invoice~) devrait étre isolée : la seule raison pour laquelle
|
||||
la classe ~Invoice~ devrait étre mise à jour est le changement de logique de calul du total (méthode
|
||||
~calculate_total~).
|
||||
* La logique de sauvegarde d'une facture (méthode ~save_to_file~) devrait elle aussi étre isolée : la classe ~Invoice~
|
||||
ne devrait pas étre mise à jour suite au changement de méthode de sauvegarde (passage d'un fichier à une BDD par ex).
|
||||
|
||||
Une implémetation respectant le principe de *responsabilité unique* :
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
class Invoice:
|
||||
|
||||
def __init__(self, book, quantity, discount_rate, tax_rate, total):
|
||||
self.book = book
|
||||
self.quantity = quantity
|
||||
self.discount_rate = discount_rate
|
||||
self.tax_rate = tax_rate
|
||||
self.total = self.calculate_total()
|
||||
|
||||
def calculate_total(self):
|
||||
price = (self.book.price - self.book.price * self.discount_rate) * self.quantity
|
||||
price_with_taxe = price * (1 + self.tax_rate)
|
||||
return price_with_taxe
|
||||
|
||||
|
||||
class InvoicePrinter:
|
||||
|
||||
def __init__(self, invoice):
|
||||
self._invoice = invoice
|
||||
|
||||
def print(self):
|
||||
print(f'{self._invoice.quantity}x {self._invoice.name} {self._invoice.price} $')
|
||||
print(f'Discount Rate: {self._invoice.discount_rate}')
|
||||
print(f'Tax Rate: {self._invoice.tax_rate}')
|
||||
print(f'Total: {self._invoice.total}')
|
||||
|
||||
|
||||
class InvoicePersistance:
|
||||
|
||||
def __init__(self, invoice):
|
||||
self._invoice = invoice
|
||||
|
||||
def save_to_file(self):
|
||||
# Creates a file with given name and writes the invoice
|
||||
...
|
||||
#+END_SRC
|
||||
|
||||
** Ouvert-fermé (Open-close principle)
|
||||
/Objects or entities should be open for extension but closed for modification./
|
||||
|
||||
Une classe doit étre *ouverte pour l'extension* et *fermée pour les modifications* :
|
||||
* Il doit étre possible d'ajouter une fonctionnalité à une classe sans modifier le code existant,
|
||||
* Réalisé à l'aide d'interfaces et classes virtuelles,
|
||||
|
||||
Exemple de classe ne respesctant pas le principe :
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
class InvoicePersistance:
|
||||
|
||||
def __init__(self, invoice):
|
||||
self._invoice = invoice
|
||||
|
||||
def save_to_file(self):
|
||||
# Creates a file with given name and writes the invoice
|
||||
...
|
||||
|
||||
def save_to_database(self):
|
||||
# Save the invoice to database
|
||||
...
|
||||
#+END_SRC
|
||||
|
||||
Il ne devrait pas étre nécessaire de modifier la classe ~InvoicePersistance~ lorsqu'une nouvelle manière de sauvegarder
|
||||
une ~Invoice~ est requise.
|
||||
|
||||
Une implémetation respectant le principe *ouvert/fermé* :
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
from abc import abstractmethod
|
||||
|
||||
class InvoicePersistance():
|
||||
|
||||
def __init__(self, invoice):
|
||||
self._invoice = invoice
|
||||
|
||||
@abstractmethod
|
||||
def save(self):
|
||||
...
|
||||
|
||||
|
||||
class FileInvoicePersistance(InvoicePersistance):
|
||||
|
||||
def save(self):
|
||||
# Creates a file with given name and writes the invoice
|
||||
...
|
||||
|
||||
|
||||
class DatabaseInvoicePersistance(InvoicePersistance):
|
||||
|
||||
def save(self):
|
||||
# Save the invoice to database
|
||||
...
|
||||
#+END_SRC
|
||||
|
||||
** Principe de substitution de Liskov
|
||||
/Let q(x) be a property provable about objects of x of type T. Then q(y) should be provable for objects y of type S where S is a subtype of T./
|
||||
|
||||
Les classes filles doivent pouvoir être substituées par leur classe mère :
|
||||
* Pour une classe B, fille de A, il doit être possible de passer une instance de B à toute méthode s'attendant à avoir une instance de A, sans disfonctionnement.
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
class Rectangle:
|
||||
|
||||
def __init__(self, width, height):
|
||||
self._width = width
|
||||
self._height = height
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
return self._width
|
||||
|
||||
@width.setter
|
||||
def width(self, width):
|
||||
self._width = width
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
return self._height
|
||||
|
||||
@height.setter
|
||||
def height(self, height):
|
||||
self._height = height
|
||||
|
||||
def get_area(self):
|
||||
return self._width * self._height
|
||||
|
||||
|
||||
class Square(Rectangle):
|
||||
|
||||
def __init__(self, size):
|
||||
super().__init__(size, size)
|
||||
|
||||
@Rectangle.width.setter
|
||||
def width(self, size):
|
||||
self._width = size
|
||||
self._height = size
|
||||
|
||||
@Rectangle.height.setter
|
||||
def height(self, size):
|
||||
self._width = size
|
||||
self._height = size
|
||||
|
||||
|
||||
def test_get_area(rectangle):
|
||||
width = rectangle.width
|
||||
rectangle.height = 10
|
||||
print(f'Expected area of {10 * width}, got {rectangle.get_area()}')
|
||||
|
||||
rectangle = Rectangle(2, 3)
|
||||
test_get_area(rectangle)
|
||||
|
||||
square = Square(2)
|
||||
square.width = 5
|
||||
test_get_area(square)
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: Expected area of 20, got 20
|
||||
: Expected area of 50, got 100
|
||||
|
||||
La classe ~Square~ ne respecte pas le principe car le comportement de la méthode ~get_area~ diffère selon l'instance de
|
||||
classe passée en paramètre.
|
||||
|
||||
** Principe de ségrégation d'interface (Interface segregation principle)
|
||||
/A client should never be forced to implement an interface that it doesn’t use, or clients shouldn’t be forced to depend on methods they do not use./
|
||||
|
||||
Il s'agit d'un principe de séparation des interfaces : plusieurs interfaces spécifiques sont meilleures qu'une unique
|
||||
générale. Ainsi, seules les méthodes nécessaires sont implémentées et non l'intégralité de celles définies par
|
||||
l'interface générique.
|
||||
|
||||
Exemple d'implémentation ne respectant pas le principe : l'interface ~ParkingLot~ englobe le stationnement
|
||||
ainsi que le paiement. Quid de son implémentation pour le cas d'un parking gratuit ?
|
||||
L'ideal serait d'isoler la partie paiement dans une interface dédiée.
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
from abc import abstractmethod
|
||||
|
||||
class Car:
|
||||
...
|
||||
|
||||
|
||||
class ParkingLot:
|
||||
|
||||
@abstractmethod
|
||||
def park_car(self):
|
||||
# Decrease empty spot count by 1
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def unpark_car(self):
|
||||
# Increase empty spot count by 1
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def get_capacity(self):
|
||||
# Return car capacity
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def calculate_fee(self, car):
|
||||
# Return the price based on the number of hours
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def do_payment(self, car):
|
||||
# Do the payment process for the computed fee
|
||||
...
|
||||
|
||||
class FreeParking(ParkingLot):
|
||||
|
||||
def park_car(self):
|
||||
...
|
||||
|
||||
def unpark_car(self):
|
||||
...
|
||||
|
||||
def get_capacity(self):
|
||||
...
|
||||
|
||||
def calculate_fee(self, car):
|
||||
# Unused method here... the parking is free.
|
||||
...
|
||||
|
||||
def do_payment(self, car):
|
||||
# Unused method here... the parking is free.
|
||||
...
|
||||
#+END_SRC
|
||||
|
||||
** Principe d'inversion de dépendence (Dependency inversion principle)
|
||||
/Entities must depend on abstractions, not on concretions. It states that the high-level module must not depend on the
|
||||
low-level module, but they should depend on abstractions./
|
||||
|
||||
Les classes devraient être baséees sur des interfaces ou des classes abstraites plutôt que des classes concrètes,
|
||||
|
||||
#+BEGIN_SRC python :results output
|
||||
class SqlConnection:
|
||||
|
||||
def connect(self):
|
||||
...
|
||||
|
||||
class PasswordReminder:
|
||||
|
||||
def __init__(self, connection: SqlConnection) -> None:
|
||||
...
|
||||
#+END_SRC
|
||||
|
||||
La classe ~PasswordReminder~ ne doit pas avoir de couplage fort avec la méthode employée pour obtenir le mot de
|
||||
passe. L'usage d'une interface permettrait d'abstraire la méthode de collecte.
|
||||
|
||||
#+BEGIN_SRC python :results outputs
|
||||
from abc import abstractmethod
|
||||
|
||||
class Connection:
|
||||
|
||||
@abstractmethod
|
||||
def connect(self):
|
||||
...
|
||||
|
||||
class SqlConnection(Connection):
|
||||
|
||||
def connect(self):
|
||||
...
|
||||
|
||||
class PasswordReminder:
|
||||
|
||||
def __init__(self, connection: Connection) -> None:
|
||||
...
|
||||
#+END_SRC
|
||||
|
||||
* Références
|
||||
* [[https://fi.ort.edu.uy/innovaportal/file/2032/1/design_principles.pdf][Uncle bob design principes]]
|
||||
* [[https://www.freecodecamp.org/news/solid-principles-explained-in-plain-english/][SOLID principes explained in plain english - freecodecamp.org]]
|
30
20220926120504-get_things_done.org
Normal file
@@ -0,0 +1,30 @@
|
||||
:PROPERTIES:
|
||||
:ID: 8d548f9b-2a7c-40c3-8538-b14c2926b865
|
||||
:mtime: 20220926123315
|
||||
:ctime: 20220926120504
|
||||
:END:
|
||||
#+title: Get Things Done
|
||||
|
||||
* Introduction
|
||||
* Méthode créée par David Allen,
|
||||
* Gestion du workflow de tâches, composé des étapes suivantes :
|
||||
* *Capturer* tout ce qui traverse son esprit (idées, taches, liens à explorer), rien n'est trop petit ou grand,
|
||||
* *Clarifier* ce qui a été précédemment capturé sous forme de tâches,
|
||||
* *Organiser* les réunions dans l'agenda, les táches dans les différents projets, définir quelles sont les prochaines
|
||||
actions à réaliser, et si celles-ci nécessitent moins
|
||||
de 2mins, les faire,
|
||||
* *Revoir/mettre à jour* l'agenda, l'/inbox/ et les différentes táches. Les objectifs de cette étape sont les
|
||||
suivants :
|
||||
* Vider sa tête des choses à retenir (idéé, tâche, rendez-vous) afin de se concentrer sur la réalisation des
|
||||
tâches : mise à jour de l'inbox,
|
||||
* Avoir un planning et des listes de tâches à jour (contenu, priorités, dépendances entre celles-ci),
|
||||
* *Réaliser les tâches plannifiées* d'après le contexte, les temps et energie disponibles et la priorité des tâches.
|
||||
|
||||
#+DOWNLOADED: https://www.ionos.com/startupguide/fileadmin/StartupGuide/Schaubilder/EN-getting-things-done-workflow.png @ 2022-09-26 12:17:54
|
||||
#+ATTR_ORG: :width 1024
|
||||
[[file:Introduction/EN-getting-things-done-workflow_2022-09-26_12-17-54.png]]
|
||||
|
||||
* Références
|
||||
* [[https://www.ionos.com/startupguide/productivity/getting-things-done-gtd/][Getting things done - Ionos]]
|
||||
** Usage avec org-mode
|
||||
* [[https://github.com/rougier/emacs-gtd][emacs-gtd - Rougier]]
|
39
20220927093748-endlessh.org
Normal file
@@ -0,0 +1,39 @@
|
||||
:PROPERTIES:
|
||||
:ID: 1ed652bc-bdcc-4410-a207-fb470df29e71
|
||||
:mtime: 20220927114630
|
||||
:ctime: 20220927093748
|
||||
:END:
|
||||
#+title: endlessh
|
||||
|
||||
* Introduction
|
||||
Outil permettant de ralentir les tentatives de connexions SSH sur le port 22 en envoyant une bannière très lentement
|
||||
(client SSH bloqué pendant des heures), l'idée étant de se connecter depuis un autre port.
|
||||
|
||||
* Installation
|
||||
#+BEGIN_SRC shell
|
||||
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
|
||||
sed -i 's/#Port 22/Port 2222/g' /etc/ssh/sshd_config
|
||||
systemctl restart sshd
|
||||
|
||||
apt install endlessh
|
||||
mkdir /etc/endlessh
|
||||
cat >/etc/endlessh/config <<EOF
|
||||
Port 22
|
||||
EOF
|
||||
|
||||
setcap 'cap_net_bind_service=+ep' /usr/bin/endlessh
|
||||
mkdir /etc/systemd/system/endlessh.service.d/
|
||||
cat /etc/systemd/system/endlessh.service.d/override.conf <<EOF
|
||||
[Service]
|
||||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
PrivateUsers=false
|
||||
EOF
|
||||
systemctl daemon-reload
|
||||
systemctl restart endlessh.service
|
||||
#+END_SRC
|
||||
|
||||
* Références
|
||||
* [[https://github.com/skeeto/endlessh][endlessh - github]]
|
||||
* [[https://www.digitalocean.com/community/tutorials/how-to-set-up-an-endlessh-tarpit-on-ubuntu-22-04][How To Set Up an Endlessh Tarpit on Ubuntu 22.04 - DigitalOcean]]
|
||||
|
||||
|
86
20220927123818-mastodon.org
Normal file
@@ -0,0 +1,86 @@
|
||||
:PROPERTIES:
|
||||
:ID: 056e86ae-99ad-45c6-be11-fe6582028870
|
||||
:mtime: 20221229104009
|
||||
:ctime: 20220927123818
|
||||
:END:
|
||||
#+title: mastodon
|
||||
|
||||
* Introduction
|
||||
Service de microblogging open-source et décentalisée.
|
||||
|
||||
* Installation
|
||||
#+BEGIN_SRC shell
|
||||
# Mastodon requires nodejs 16
|
||||
sudo snap install node --classic
|
||||
|
||||
apt install imagemagick ffmpeg libpq-dev libxml2-dev libxslt1-dev file git-core \
|
||||
g++ libprotobuf-dev protobuf-compiler pkg-config nodejs gcc autoconf \
|
||||
bison build-essential libssl-dev libyaml-dev libreadline6-dev \
|
||||
zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev \
|
||||
nginx redis-server redis-tools postgresql postgresql-contrib \
|
||||
certbot python3-certbot-nginx libidn11-dev libicu-dev libjemalloc-dev
|
||||
|
||||
yarn set version stable
|
||||
|
||||
# We will be using rbenv to manage Ruby versions, because it’s easier to get the right versions and
|
||||
# to update once a newer release comes out. rbenv must be installed for a single Linux user,
|
||||
# therefore, first we must create the user Mastodon will be running as:
|
||||
adduser --disabled-login mastodon
|
||||
|
||||
# The following command shall be run using root priviledges (sudo)
|
||||
su - mastodon
|
||||
# Proceed to install rbenv and rbenv-build:
|
||||
git clone https://github.com/rbenv/rbenv.git ~/.rbenv
|
||||
echo 'eval "$(~/.rbenv/bin/rbenv init - bash)"' >> ~/.bashrc
|
||||
git clone https://github.com/rbenv/ruby-build.git ~/.rbenv/plugins/ruby-build
|
||||
RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install 3.0.3
|
||||
rbenv global 3.0.3
|
||||
gem install bundler --no-document
|
||||
exit
|
||||
|
||||
# Creating mastodon user in postgres
|
||||
sudo -u postgres psql
|
||||
#+END_SRC
|
||||
#+BEGIN_SRC sql
|
||||
CREATE USER mastodon CREATEDB;
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC shell
|
||||
# The following command shall be run using root priviledges (sudo)
|
||||
su - mastodon
|
||||
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash -
|
||||
nvm install v16.17.1
|
||||
npx browserslist@latest --update-db
|
||||
|
||||
git clone https://github.com/tootsuite/mastodon.git live && cd live
|
||||
git checkout $(git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)
|
||||
sed -i 's/\([ ]*"emoji-mart": \)"[^"]*",/\1"^3.0.1",/' package.json
|
||||
|
||||
bundle config deployment 'true'
|
||||
bundle config without 'development test'
|
||||
bundle install -j$(getconf _NPROCESSORS_ONLN)
|
||||
yarn install --pure-lockfile
|
||||
|
||||
RAILS_ENV=production bundle exec rake mastodon:setup
|
||||
|
||||
exit
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC shell
|
||||
cp /home/mastodon/live/dist/nginx.conf /etc/nginx/sites-available/mastodon
|
||||
sed -i 's/example.com/mastodon.adrien.run/' /etc/nginx/sites-available/mastodon
|
||||
sed -i 's/\([ ]*server 127.0.0.1\):3000/\1:3001/' /etc/nginx/sites-available/mastodon
|
||||
sed -i 's/\# \(ssl_certificate[ ]*.*\)/\1/' /etc/nginx/sites-available/mastodon
|
||||
|
||||
certbot --nginx -d example.com
|
||||
ln -s /etc/nginx/sites-available/mastodon /etc/nginx/sites-enabled/mastodon
|
||||
|
||||
cp /home/mastodon/live/dist/mastodon-*.service /etc/systemd/system/
|
||||
sed -i 's/\(Environment="PORT\)=3000/\1=3001/' /etc/systemd/system/mastodon-web.service
|
||||
systemctl daemon-reload
|
||||
|
||||
#+END_SRC
|
||||
|
||||
* Références
|
||||
* [[https://docs.joinmastodon.org/admin/install/][Installing from source - Mastodon documentation]]
|
71
20220928113147-heap_sort_algorithm.org
Normal file
@@ -0,0 +1,71 @@
|
||||
:PROPERTIES:
|
||||
:ID: 6af01039-a0a9-46fc-abe8-82f9662bc4b7
|
||||
:mtime: 20220928120648
|
||||
:ctime: 20220928113147
|
||||
:END:
|
||||
#+title: heap sort algorithm
|
||||
|
||||
* Introduction
|
||||
* Algorithme de classement /in-place/ d'un tableau en le divisant en deux sous-tableaux contenant les éléments classés et non
|
||||
classés,
|
||||
* Efficace : *O(nlog(n))* où n correspond au nombre d'éléments à classer,
|
||||
* Le éléments non classés sont organisés dans une /heap data structure/,
|
||||
* A chaque étape, l'élément max/min se trouvant à la racine du /heap/ est déplacé dans le sous-tableau des éléments
|
||||
classés jusqu'à ce qu'il ne reste qu'un élément dans le sous-tableau des éléments non classés,
|
||||
|
||||
* Organisation des éléments dans le tableau
|
||||
#+DOWNLOADED: https://miro.medium.com/max/720/1*KSt2oqlq_mbPK3t1RE-WFQ.png @ 2022-09-28 11:43:09
|
||||
[[file:Organisation des éléments dans le tableau/1*KSt2oqlq_mbPK3t1RE-WFQ_2022-09-28_11-43-09.png]]
|
||||
|
||||
* Implémentation
|
||||
#+BEGIN_SRC python :results output
|
||||
from typing import Any, List
|
||||
|
||||
def heap_sort(array: List[Any]):
|
||||
build_max_heap(array)
|
||||
# start with the ending index all the way to 0
|
||||
for end_index in range(len(array)-1, 0, -1):
|
||||
swap(array, 0, end_index)
|
||||
# reduce heap size by 1
|
||||
# sift down the value we just swapped
|
||||
heapify(0, end_index - 1, array)
|
||||
# return array
|
||||
|
||||
def build_max_heap(array: List[Any]):
|
||||
last_non_leaf_node_index = (len(array) - 2) // 2
|
||||
for index in range(last_non_leaf_node_index, -1, -1):
|
||||
heapify(index, len(array)-1, array)
|
||||
|
||||
# sift down
|
||||
def heapify(current_index: int, end_index: int, array: List[Any]):
|
||||
left_child_index = 2 * current_index + 1
|
||||
while left_child_index <= end_index:
|
||||
right_child_index = 2 * current_index + 2 if (2 * current_index + 2 <= end_index) else -1
|
||||
|
||||
largest_child_index = left_child_index
|
||||
if right_child_index != -1 and array[left_child_index] < array[right_child_index]:
|
||||
largest_child_index = right_child_index
|
||||
|
||||
if array[current_index] < array[largest_child_index]:
|
||||
swap(array, current_index, largest_child_index)
|
||||
current_index = largest_child_index
|
||||
left_child_index = 2 * current_index + 1
|
||||
else:
|
||||
return
|
||||
|
||||
def swap(array: List[Any], i: int, j: int):
|
||||
array[i], array[j] = array[j], array[i]
|
||||
|
||||
array = [1, -15, 22, 40, 9, 91]
|
||||
print(f"Before sorting: {array}")
|
||||
heap_sort(array)
|
||||
print(f"After sorting: {array}")
|
||||
#+END_SRC
|
||||
|
||||
#+RESULTS:
|
||||
: Before sorting: [1, -15, 22, 40, 9, 91]
|
||||
: After sorting: [-15, 1, 9, 22, 40, 91]
|
||||
|
||||
* Référence
|
||||
* [[https://yuminlee2.medium.com/heap-sort-algorithm-6e200dc51845][Heap Sort Algorithm. A in-place sorting algorithm that sorts… - Medium]]
|
||||
|
37
20221001210655-framadate.org
Normal file
@@ -0,0 +1,37 @@
|
||||
:PROPERTIES:
|
||||
:ID: 8bb29bf5-219f-49ff-b410-e7cc2473337f
|
||||
:mtime: 20221002111411
|
||||
:ctime: 20221001210655
|
||||
:END:
|
||||
#+title: framadate
|
||||
|
||||
* Introduction
|
||||
Service pouvant être hébergé sur son propre server et proposant une alternative à /doodle/.
|
||||
|
||||
* Installation
|
||||
#+BEGIN_SRC shell
|
||||
apt install php-pgsql php php-intl php-mbstring
|
||||
# The following command shall be run using root priviledges (sudo)
|
||||
mysql -u root -p
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC sql
|
||||
CREATE DATABASE IF NOT EXISTS `framadate` DEFAULT CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;
|
||||
CREATE USER 'framadate'@'localhost' IDENTIFIED BY 'useastrongpassword';
|
||||
GRANT ALL PRIVILEGES ON `framadate`.* TO 'framadate'@'localhost';
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC shell
|
||||
adduser --disabled-login framadate
|
||||
# The following command shall be run using root priviledges (sudo)
|
||||
su - framadate
|
||||
wget https://packages.framasoft.org/projects/framadate/framadate-1.1.19.zip -P .
|
||||
unzip ./framadate-1.1.19.zip
|
||||
|
||||
chown -R www-data: /home/framadate/framadate
|
||||
sudo -u www-data htpasswd -bc /home/framadate/framadate/admin/.htpasswd admin 'admin_password'
|
||||
#+END_SRC
|
||||
|
||||
* Références
|
||||
* [[https://framagit.org/framasoft/framadate/framadate/-/wikis/home][Framadate · GitLab]]
|
||||
|
145
20230520112339-readflow.org
Normal file
@@ -0,0 +1,145 @@
|
||||
:PROPERTIES:
|
||||
:ID: af021596-3d07-42bf-9131-0c203ac1c26f
|
||||
:mtime: 20230521180253
|
||||
:ctime: 20230520112339
|
||||
:END:
|
||||
#+title: readflow
|
||||
|
||||
* Introduction
|
||||
Sauvegarde de page web pour lecture offline.
|
||||
|
||||
* Installation
|
||||
** API
|
||||
*** Build
|
||||
#+BEGIN_SRC shell
|
||||
cd /opt/
|
||||
git clone https://github.com/ncarlier/readflow.git readflow
|
||||
cd readflow
|
||||
git submodule init
|
||||
git submodule update
|
||||
make
|
||||
#+END_SRC
|
||||
*** Configuration
|
||||
**** Préparation des variables d'environnement
|
||||
Contenu du fichier ~env~:
|
||||
#+BEGIN_SRC shell
|
||||
export READFLOW_DB="postgres://<db_user>:<db_pass>@localhost/readflow"
|
||||
export READFLOW_LISTEN_ADDR="localhost:8010"
|
||||
export READFLOW_LISTEN_METRICS=
|
||||
export READFLOW_AUTHN="https://login.adrien.run/realms/readings"
|
||||
export READFLOW_PUBLIC_URL="https://readflow.adrien.run"
|
||||
export READFLOW_SECRET_SALT="<salt>"
|
||||
export READFLOW_BLOCK_LIST=
|
||||
export READFLOW_BROKER_URI=
|
||||
export READFLOW_WEB_SCRAPER_URL=
|
||||
export READFLOW_IMAGE_PROXY_URL=
|
||||
export READFLOW_AVATAR_PROVIDER=
|
||||
export READFLOW_SECRETS_ENGINE_PROVIDER=
|
||||
export READFLOW_SENTRY_DSN=
|
||||
export READFLOW_POCKET_CONSUMER_KEY=
|
||||
|
||||
export REACT_APP_API_ROOT="/api"
|
||||
export REACT_APP_AUTHORITY="https://login.adrien.run/realms/readings"
|
||||
export REACT_APP_CLIENT_ID="readflow"
|
||||
export REACT_APP_REDIRECT_URL="https://readflow.adrien.run/login"
|
||||
#+END_SRC
|
||||
**** Substitution des variables du fichier de configuration
|
||||
#+BEGIN_SRC shell
|
||||
source ./env
|
||||
envsubst < ./readflow.toml > ./config.toml
|
||||
#+END_SRC
|
||||
*** Exécution
|
||||
#+BEGIN_SRC shell
|
||||
./release/readflow -config ./config.toml
|
||||
#+END_SRC
|
||||
Ou
|
||||
#+BEGIN_SRC shell
|
||||
cat >/lib/systemd/system/readflow.service <<EOF
|
||||
[Unit]
|
||||
Description=Readflow service
|
||||
|
||||
[Service]
|
||||
User=readflow
|
||||
ExecStart=/opt/readflow/release/readflow -config /opt/readflow/config.toml
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
SyslogIdentifier=readflow
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
#+END_SRC
|
||||
#+BEGIN_SRC shell
|
||||
adduser --system --no-create-home --disabled-password --disabled-login readflow
|
||||
systemctl enable readflow
|
||||
systemctl start readflow
|
||||
#+END_SRC
|
||||
|
||||
** Webclient
|
||||
#+BEGIN_SRC shell
|
||||
n lts # Require a up to date node version
|
||||
npm install --legacy-peer-deps
|
||||
npm run build
|
||||
#+END_SRC
|
||||
|
||||
** Nginx
|
||||
#+BEGIN_SRC conf
|
||||
server {
|
||||
server_name readflow.adrien.run;
|
||||
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
# SSL configuration
|
||||
include /etc/nginx/ssl.conf;
|
||||
ssl_certificate /etc/letsencrypt/live/readflow.adrien.run/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/readflow.adrien.run/privkey.pem;
|
||||
|
||||
# Logging configuration
|
||||
access_log /var/log/nginx/readflow.access.log;
|
||||
error_log /var/log/nginx/readflow.error.log;
|
||||
|
||||
gzip on;
|
||||
gzip_static on; # allows pre-serving of .gz file if it exists
|
||||
gzip_disable "msie6"; # Disable for user-agent Internet explorer 6. Not supported.
|
||||
gzip_proxied any; # enable gzip for all proxied requests
|
||||
gzip_buffers 16 8k; # number and size of buffers to compress a response
|
||||
gzip_http_version 1.1;
|
||||
gzip_min_length 256; # Only gzip files of size in bytes
|
||||
gzip_types text/plain text/css text/html application/javascript application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
|
||||
gunzip on;
|
||||
|
||||
add_header 'Access-Control-Allow-Origin' 'https://login.adrien.run';
|
||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
||||
|
||||
location /api {
|
||||
rewrite /api/(.*) /$1 break;
|
||||
|
||||
proxy_redirect off;
|
||||
proxy_pass http://127.0.0.1:8010;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
root /opt/readflow/ui/build;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
server_name readflow.adrien.run;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
if ($host = readflow.adrien.run) {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
return 404;
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
* Références
|
||||
* [[https://github.com/ncarlier/readflow][Readflow - Github]]
|
||||
* [[https://github.com/ncarlier/readflow/issues/48][Can a simple tutorial be provided for non-professionals #48 - Github]]
|
99
20230520122106-keycloak.org
Normal file
@@ -0,0 +1,99 @@
|
||||
:PROPERTIES:
|
||||
:ID: e0695c59-6fd5-4074-81ca-8e14ec965bbd
|
||||
:mtime: 20230521180042
|
||||
:ctime: 20230520122106
|
||||
:END:
|
||||
#+title: keycloak
|
||||
|
||||
* Introduction
|
||||
Service open-source de gestion d'authentification et d'accès.
|
||||
|
||||
* Installation
|
||||
** Application
|
||||
#+BEGIN_SRC shell
|
||||
apt install openjdk-19-jre
|
||||
cd /opt/
|
||||
wget https://github.com/keycloak/keycloak/releases/download/21.1.1/keycloak-21.1.1.zip
|
||||
unzip keycloak-21.1.1.zip
|
||||
cd keycloak-21.1.1
|
||||
# bin/kc.sh start-dev
|
||||
|
||||
cat >/opt/keycloak/conf/keycloak.conf <<EOF
|
||||
db=postgres
|
||||
db-username=keycloak
|
||||
db-password=<db_password>
|
||||
proxy=edge
|
||||
hostname=login.adrien.run
|
||||
http-host=127.0.0.1
|
||||
http-port=9090
|
||||
hostname-strict-https=false
|
||||
EOF
|
||||
|
||||
bin/kc.sh build
|
||||
|
||||
cat >/lib/systemd/system/keycloak.service <<EOF
|
||||
[Unit]
|
||||
Description=Keycloak service
|
||||
|
||||
[Service]
|
||||
User=keycloak
|
||||
ExecStart=/opt/keycloak/bin/kc.sh start
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
Restart=always
|
||||
RestartSec=3
|
||||
SyslogIdentifier=keycloak
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
adduser --system --no-create-home --disabled-password --disabled-login keycloak
|
||||
chown keycloak ./data/ -R
|
||||
|
||||
systemctl enable keycloak
|
||||
systemctl start keycloak
|
||||
#+END_SRC
|
||||
|
||||
** Nginx
|
||||
#+BEGIN_SRC conf
|
||||
server {
|
||||
server_name login.adrien.run;
|
||||
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
# SSL configuration
|
||||
include /etc/nginx/ssl.conf;
|
||||
ssl_certificate /etc/letsencrypt/live/login.adrien.run/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/login.adrien.run/privkey.pem;
|
||||
|
||||
# Loggin coinfuguration
|
||||
access_log /var/log/nginx/login.access.log;
|
||||
error_log /var/log/nginx/login.error.log;
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:9090;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
server_name login.adrien.run;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
if ($host = login.adrien.run) {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
return 404;
|
||||
}
|
||||
#+END_SRC
|
||||
|
||||
* Références
|
||||
* [[https://github.com/keycloak/keycloak][Keycloak - Github]]
|
||||
|
97
20240215223404-uptime_kuma.org
Normal file
@@ -0,0 +1,97 @@
|
||||
:PROPERTIES:
|
||||
:ID: e5e49b61-ee56-4364-a96e-48d72217ef95
|
||||
:mtime: 20240217184904
|
||||
:ctime: 20240215223404
|
||||
:END:
|
||||
#+title: uptime-kuma
|
||||
|
||||
* Installation
|
||||
|
||||
#+BEGIN_SRC shell
|
||||
cd /opt
|
||||
mkdir uptime-kuma
|
||||
chown ubuntu:ubuntu uptime-kuma/
|
||||
git clone https://github.com/louislam/uptime-kuma.git
|
||||
cd uptime-kuma
|
||||
npm run setup
|
||||
npm install vite
|
||||
npm run build
|
||||
|
||||
useradd -m --system uptime
|
||||
|
||||
cat <<EOF > /usr/lib/systemd/system/update-kuma.service
|
||||
[Unit]
|
||||
Description=Uptime-Kuma - A free and open source uptime monitoring solution
|
||||
Documentation=https://github.com/louislam/uptime-kuma
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=uptime
|
||||
WorkingDirectory=/opt/uptime-kuma
|
||||
ExecStart=/bin/bash -c 'PATH=/home/uptime/.n/bin:$PATH npm run start-server'
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now uptime-kuma
|
||||
|
||||
cat <<EOF > /etc/nginx/sites-available/uptime
|
||||
server {
|
||||
server_name tools.adrien.run;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
return 404;
|
||||
}
|
||||
|
||||
server {
|
||||
server_name uptime.tools.adrien.run;
|
||||
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
|
||||
# SSL configuration
|
||||
include /etc/nginx/ssl.conf;
|
||||
ssl_certificate /etc/letsencrypt/live/uptime.tools.adrien.run/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/uptime.tools.adrien.run/privkey.pem;
|
||||
|
||||
# Logging configuration
|
||||
access_log /var/log/nginx/uptime.access.log;
|
||||
error_log /var/log/nginx/uptime.error.log;
|
||||
|
||||
root /opt/uptime-kuma;
|
||||
|
||||
location / {
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header Host $host;
|
||||
proxy_pass http://127.0.0.1:3002/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
server_name uptime.tools.adrien.run;
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
if ($host = uptime.tools.adrien.run) {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
|
||||
return 404;
|
||||
}
|
||||
EOF
|
||||
|
||||
systemctl restart nginx.service
|
||||
certbot -d uptime.tools.adrien.run --nginx
|
||||
#+END_SRC
|
BIN
Introduction/320px-Drbd-arch_2022-05-25_22-05-47.png
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
Introduction/640px-Drbd-arch_2022-05-25_22-06-08.png
Normal file
After Width: | Height: | Size: 74 KiB |
481
Introduction/Diagramme_Matrix_fr_2022-02-26_10-29-56.svg
Normal file
After Width: | Height: | Size: 284 KiB |
After Width: | Height: | Size: 45 KiB |
BIN
Introduction/LVM1_2022-03-27_10-39-39.jpg
Normal file
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 97 KiB |
After Width: | Height: | Size: 235 KiB |
BIN
Références/800px-Diagramme_Matrix_fr.svg_2022-02-26_10-14-23.png
Normal file
After Width: | Height: | Size: 192 KiB |
BIN
matrix/Diagramme_Matrix_fr.png
Normal file
After Width: | Height: | Size: 61 KiB |