diff --git a/.gitignore b/.gitignore index b43cb21..a9e1de6 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ site graph.png /preview + +.jj +.direnv diff --git a/Tuprules.tup b/Tuprules.tup index 99e66b7..a1c3ed5 100644 --- a/Tuprules.tup +++ b/Tuprules.tup @@ -1,15 +1,17 @@ &root = . +&tmpl_dir = ./templates +&gen_tmpl_dir = ./build/templates HTML_TEMPLATE = main.html -!html = | &(root)/templates/footer.html \ - |> ^ html %f^ \ +!html = | &(tmpl_dir)/ \ + |> ^b html %f^ \ pandoc --from markdown --to html \ - --template=&(root)/templates/$(HTML_TEMPLATE) \ + --template=&(tmpl_dir)/$(HTML_TEMPLATE) \ + --include-in-header=&(tmpl_dir)/header.html \ + --include-before-body=&(tmpl_dir)/nav.html \ --css &(root)/css/style.css \ - --include-in-header=&(root)/templates/header.html \ - --include-before-body=&(root)/templates/nav.html \ - --include-after-body=&(root)/templates/footer.html \ + --include-after-body=&(gen_tmpl_dir)/footer.html \ %f | sed 's|%%webRoot%%|&(root)|g' > %o \ |> %B.html @@ -20,5 +22,13 @@ HTML_TEMPLATE = main.html !compress_pdf = |> ps2pdf %f %o |> JPG_OPT = -quality 80 -strip -interlace Plane -!blur_mini = |> convert %f -resize 400x400 -blur 0x8 $(JPG_OPT) %o |> blur_mini.jpg -!thumbnail = |> convert %f -resize 200x200 $(JPG_OPT) %o |> +!blur_mini = |> ^ %f -> blur mini^ convert %f -resize 400x400 -blur 0x8 $(JPG_OPT) %o |> blur_mini.jpg +!thumbnail = |> ^ %f -> thumbnail^ convert %f -resize 200x200 $(JPG_OPT) %o |> + +# +# Slides +# +MARP = npx @marp-team/marp-cli@latest +MARP_OPTS = --allow-local-files --bespoke.progress +!marp_pdf = |> $(MARP) $(MARP_OPTS) %f --pdf --output %o |> %B.pdf +!marp_html = |> $(MARP) $(MARP_OPTS) %f --html --output %o |> %B.html diff --git a/about.md b/about.md index 4d59c46..7a69288 100644 --- a/about.md +++ b/about.md @@ -29,18 +29,15 @@ sail again. In 2010 I moved to Oslo, Norway, to work as a [Qt](http://www.qt.io/) software engineer for [Nokia](http://www.nokia.com/) with the great people of Trolltech. -But in the end, I decided Nokia's new direction with Windows Phone didn't suit -me so I decided to fly back to France. - -Damn I missed croissants. +I learned a lot with such a bunch of talented people in different fields +(graphics, web, filesystem, etc). ### 2011 - Computer vision In 2011 I had the chance to work on computer vision projects. I joined [LTU technologies](http://www.ltutech.com/) as a research engineer in Paris, France. -I implemented exciting computer vision stuff (image matching, retrieval, etc), -following the state of the art in the field. Unfortunately LTU shut down in -2015. +I implemented exciting computer vision stuff (image matching, retrieval, +similarity, etc), following the state of the art in the field. ### 2015 - Camera software @@ -52,15 +49,22 @@ working on the firmware level and I learned a ton about photography. ### 2017 - Maps -In 2017 I joined [Zenly](http://zen.ly). We made a social app with a strong -focus on the map, putting the fun back in map apps. +In 2017 I joined [Zenly](http://zen.ly) in Paris. We made a social app +with a strong focus on the map, putting the fun back in map apps. Although it +looked "simple", it involved a lot of technology, with a very custom tech stack. ### 2020 - Renewable energy -In 2020 I joined [MoMA](https://www.momagroup.com/) to work on the +In 2020 I joined [MoMA](https://www.momagroup.com/) in Paris again, to work on the [E6](https://www.e6-group.com/) project. I felt it was the right time to work on current matters such as energy. +### 2022 - Smart home + +In 2022 I joined [Netatmo](https://www.netatmo.com/) in Boulogne-Billancourt to +work on smart homes. I work in the Vision team, making home cameras smarter. I +am thrilled to work on computer vision again. +
Mastodon diff --git a/articles/Tupfile b/articles/Tupfile index c8d9bfc..924243a 100644 --- a/articles/Tupfile +++ b/articles/Tupfile @@ -1,5 +1,5 @@ include_rules HTML_TEMPLATE = article.html -: *.md |> ./generate_listing.sh > %o |> index.md +: *.md |> ./generate_listing.nu > %o |> index.md : foreach *.md |> !html |> diff --git a/articles/generate_listing.nu b/articles/generate_listing.nu new file mode 100755 index 0000000..2af678a --- /dev/null +++ b/articles/generate_listing.nu @@ -0,0 +1,40 @@ +#!/usr/bin/env nu +# +def title [path: string] -> string { + open $path | lines | filter {|l| (str starts-with "title:")} | first | split row --regex 'title\s*:\s*' | get 1 | str trim --char "\"" +} + +def creation_date [path: string] -> string { + open $path | lines | filter {|l| (str starts-with "date:")} | first | split row --regex '\s*:\s*' | get 1 +} + +def update_date [path: string] -> string? { + let updates = open $path | lines | filter {|l| (str starts-with "update:")} + if ($updates | length) > 0 { + return ($updates | first | split row --regex '\s*:\s*' | get 1) + } else { + return null + } +} + +let pages = (glob *.md) ++ (glob **/index.md) +let sorted_pages = $pages | wrap 'path' + | upsert title {|row| (title $row.path)} + | upsert creation {|row| (creation_date $row.path)} + | upsert update {|row| (update_date $row.path)} + | sort-by --reverse creation + +print "--- +title: Articles +--- +" + +$sorted_pages | each {|p| + let rel_path = $p.path | path relative-to (pwd) + print --no-newline $"- ($p.creation): [($p.title)]\(($rel_path)\)" + if $p.update? != null { + print $" \(Updated: ($p.update)\)" + } else { + print "" + } +} diff --git a/articles/git_large_files.md b/articles/git_large_files.md new file mode 100644 index 0000000..f64a522 --- /dev/null +++ b/articles/git_large_files.md @@ -0,0 +1,110 @@ +--- +title: Git and large files +date: 2021-12-29 +--- + +Git is a cornerstone of software development nowadays, it has become the +de-facto version control system. + +Its interface is a bit complex to work with but a lot of tooling has been +developed over the years that lessen the pain to deal with it. + +One shortcoming of git though (and version control system in general), is +dealing with huge binary files. These files are usually media assets that are +not meant to be diffable, but they do belong to the project nonetheless. + +They are different ways to deal with these files: + +### 1. treat them like regular text files + +This is the easiest solution: do nothing special. It works perfectly and you +keep a clean history. However, as you modify your assets, the repository size +will grow and it will become slower to clone on your CI pipeline. It will also +put more charge on your git server. + +### 2. keep them out of your repository + +Out of the repository, out of trouble! If you keep your large assets in a +separate directory (Dropbox for instance), your repository will stay light. But +now you need to synchronize your external storage with your repository for your +project. Most of the time, only the latest version is kept around, making it +impossible to inspect an older revision with the appropriate assets. + +### 3. store a pointer to external storage + +As a compromise, you can store a pointer to external storage in your repository. +Everytime you checkout a specific revision, you will fetch the according data to +external storage and inject it into the project. + + +The solution 3. is the more convenient solution: we keep regular git workflow, +and put the burden of hosting large files out of git itself. + +## Git Large File Storage + +[Git Large File Storage](https://git-lfs.github.com/) (Git LFS) is the more +widespread implementation of this mecanism. It is developed by GitHub and is +available on all repositories on their platform. It works out of the box: you +set it once and you can forget about it. + +However, there are some shortcomings with Git LFS. + +### 1. your project is now longer self-contained in git + +If you decide to use Git LFS, you will tie your project with the LFS storage +server. You won't be able to walk through your history without having a storage +server. GitHub LFS server implementation is currently closed-source and only a +"non production ready" reference server is available. + +Major hosting platforms have implemented their own implementation and it is +possible to migrate your data among compatibles hosting platforms. But your +local copy of the repository will never hold all the data needed for your +project. In a way, the storage server becomes a centralized piece. You can fetch +all data locally to have it available but it won't be considered a source, it is +more like a cache. + +### 2. you can't easily manage storage in LFS + +If you commit a bunch of files, then push your changes, all the files will be +stored on the LFS server. If you want to remove them (eg. you uploaded unwanted +files), you can do it locally by doing a rebase, then call `git lfs prune`. +However, that will only clean up your local copies of files. What has been +pushed will stay on the server. + +If you wish to remove files from the server, your options depend on the server +implementation: +- on GitHub, your only option to reclaim LFS quota and truly delete files from + LFS is to [delete and recreate your repository](https://docs.github.com/en/repositories/working-with-files/managing-large-files/removing-files-from-git-large-file-storage#git-lfs-objects-in-your-repository) +- on BitBucket Cloud, you can browse LFS files in the web UI and delete specific + files + +## Git Annex + +[git-annex](https://git-annex.branchable.com/) is a complete solution to deal +with external files in your git repository. It is also more complex than Git +LFS. As you can see in their +[walkthrough](https://git-annex.branchable.com/walkthrough/), you need to +explicitly set remotes for your files, and sync content between remotes. + +Data is shared among local repositories in `.git/annex`, but it won't be +available in common source forges such as GitHub. To make this data available to +all people in the project, you can use [special +remotes](https://git-annex.branchable.com/special_remotes/) which are used as +data storage stores, akin to Git lFS (which can be used as a special remote). + +Contrary to Git LFS, you can see what content is currently +[unused](https://git-annex.branchable.com/walkthrough/unused_data/), [delete +unwanted files](https://git-annex.branchable.com/tips/deleting_unwanted_files/). +It is a more complex solution but it is more flexible. + +## What I recommend + +I think git-annex gives the user more control over its data: it can be fully +decentralized and offers tools to manage its content. + +Git LFS is simpler and more widely used, but once you hit one of its limitation, +it can be costly to break free. + +## Links + +- [Large files with Git: LFS and git-annex](https://lwn.net/Articles/774125/) diff --git a/articles/jujutsu/Tupfile b/articles/jujutsu/Tupfile new file mode 100644 index 0000000..df556c8 --- /dev/null +++ b/articles/jujutsu/Tupfile @@ -0,0 +1,6 @@ +include_rules +HTML_TEMPLATE = article.html + +: slides.md |> !marp_pdf |> jujutsu_slides.pdf ./ +: index.md | ./ |> !html |> + diff --git a/articles/jujutsu/index.md b/articles/jujutsu/index.md new file mode 100644 index 0000000..78dcf25 --- /dev/null +++ b/articles/jujutsu/index.md @@ -0,0 +1,16 @@ +--- +title: "Lightning talk: Jujutsu" +date: 2024-11-26 +--- + +_This article is also available as a lightning talk: [pdf](./jujutsu_slides.pdf)_ + +## What is it? + +## How does it compare? + +## VCS landscape +> I was part of the team at Meta that built Sapling for many years. I’m no +> longer at Meta and I use jj full time. +> +> _[Discussion on Lobste.rs](https://lobste.rs/s/rojoz1/jujutsu_jj_git_compatible_vcs#c_foqya4)_ diff --git a/articles/jujutsu/slides.md b/articles/jujutsu/slides.md new file mode 100644 index 0000000..b3ab148 --- /dev/null +++ b/articles/jujutsu/slides.md @@ -0,0 +1,23 @@ +--- +marp: true +theme: gaia +footer: '**Fabien Freling** - 2024-11-26' +paginate: true +--- + + + + + + +# Jujutsu + +Life after Git + +--- diff --git a/articles/web_stack.md b/articles/web_stack.md index 1ffc6d8..bface29 100644 --- a/articles/web_stack.md +++ b/articles/web_stack.md @@ -1,6 +1,7 @@ --- title: Web stack date: 2019-06-26 +update: 2024-11-26 --- Previous stacks diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..6bc678b --- /dev/null +++ b/flake.lock @@ -0,0 +1,25 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1731890469, + "narHash": "sha256-D1FNZ70NmQEwNxpSSdTXCSklBH1z2isPR84J6DQrJGs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "5083ec887760adfe12af64830a66807423a859a7", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..df507e3 --- /dev/null +++ b/flake.nix @@ -0,0 +1,22 @@ +{ + description = "Website"; + + outputs = { self, nixpkgs }: + let pkgs = nixpkgs.legacyPackages.x86_64-linux; + in { + devShell.x86_64-linux = with pkgs; + mkShell { + nativeBuildInputs = [ + graphviz-nox + imagemagick + just + libavif + libjxl + nodejs + nushell + pandoc + tup + ]; + }; + }; +} diff --git a/justfile b/justfile index 833f577..36a8e8f 100644 --- a/justfile +++ b/justfile @@ -19,7 +19,7 @@ upload-resume: deploy: build rsync --checksum --copy-links -ave 'ssh' \ --exclude-from=rsync_excludes.txt \ - build/* fabs@ffreling.com:ffreling.com/ + build/* fabs@ffreling.com:/var/www/ffreling.com/ preview: build python3 -m webbrowser -t "file://{{root}}/build/index.html" diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..0753dc8 --- /dev/null +++ b/shell.nix @@ -0,0 +1,12 @@ +{ pkgs ? import {} }: + +pkgs.mkShell { + buildInputs = with pkgs; [ + imagemagick + just + libavif + nushell + pandoc + tup + ]; +} diff --git a/templates/Tupfile b/templates/Tupfile index 45e0fb0..f179092 100644 --- a/templates/Tupfile +++ b/templates/Tupfile @@ -1 +1 @@ -: |> ./generate_footer.sh > %o |> footer.html +: |> ./generate_footer.sh > %o |> footer.html ./ diff --git a/templates/nav.html b/templates/nav.html index ca41a64..3e2ab4a 100644 --- a/templates/nav.html +++ b/templates/nav.html @@ -5,3 +5,4 @@ Articles About
+