<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"><channel><title>Benjamin Bouvier's world</title><link>https://bouvier.cc/</link><description></description><lastBuildDate>Wed, 27 Apr 2022 23:17:23 +0200</lastBuildDate><item><title>cargo-machete, find unused dependencies quickly</title><link>https://bouvier.cc/cargo-machete/</link><description>&lt;hr&gt;
&lt;p&gt;&lt;code&gt;cargo-machete&lt;/code&gt; is a new Cargo tool that detects unused dependencies in Rust
projects, in a fast (yet imprecise) way. As of today you can install it with
&lt;code&gt;cargo install cargo-machete&lt;/code&gt; and then run it with &lt;code&gt;cargo machete&lt;/code&gt; from any
folder that contains a workspace or crate, to find if you have potentially
unused dependencies. Beware, it can report a few false positives!&lt;/p&gt;
&lt;h2 id="problem-statement"&gt;&lt;a class="toclink" href="#problem-statement"&gt;Problem statement&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When developers hack on code, it's a pretty common to reuse software that
already exists and has been written, optimized, and battle-tested by many
others. In fact, that's a core idea of the open-source movement, and one
historical reason for its existence.&lt;/p&gt;
&lt;p&gt;When zooming in into the Rust programming language case, my opinion is that it
is also a key reason why Rust has been so successful: having plenty of crates
doing everything you might need, already implemented for you and at hand's
reach on &lt;code&gt;crates.io&lt;/code&gt;. Plus, having the wonder of a one-does-it-all Cargo tool
that makes it very easy to use those crates as dependencies in your project.
&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;However, this comes with a price: sometimes you add a dependency because it's
useful at a particular point in time. Much later, it's not useful anymore, but
you may have forgotten about it. And then, the dependency remains as a zombie
in your &lt;code&gt;Cargo.toml&lt;/code&gt; file. Cargo will include it in the compilation graph,
despite the compilation artifacts not being used at all. The unused dependency
will just stay there, silently weep, waiting for you to recall it exists.&lt;/p&gt;
&lt;p&gt;Of course, the problem can even become worse: maybe you maintain several crates
that have unused dependencies. Or maybe you work with many crates as part of a
workspace, and each may have unused dependencies. Or simply you use many
dependencies yourself, and some may include unused dependencies. If you've
published your crates and others use those, then everyone could also compile
unused dependencies. At the scale of the entire Rust crates ecosystem, it can
have a huge impact on the compile times, produced heat and wasted energy.&lt;/p&gt;
&lt;h2 id="have-you-heard-about-our-lord-and-savior-cargo-udeps"&gt;&lt;a class="toclink" href="#have-you-heard-about-our-lord-and-savior-cargo-udeps"&gt;Have you heard about our lord and savior, &lt;code&gt;cargo-udeps&lt;/code&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There's already a nice tool for this in the ecosystem:
&lt;a href="https://github.com/est31/cargo-udeps"&gt;&lt;code&gt;cargo-udeps&lt;/code&gt;&lt;/a&gt;. It will compile your
crate (or workspace) and then infer from the compiled artifacts what
dependencies are used by your project, and thus show you which dependencies are
&lt;em&gt;unused&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;That's great, but the way it works forces a few tradeoffs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it requires to compile the whole crate with the Rustc &lt;code&gt;nightly&lt;/code&gt; compiler. For
  me that means recompiling the whole project from scratch, most of the time,
  since I'm mostly using stable rustc as my daily driver.&lt;/li&gt;
&lt;li&gt;if you compile for multiple targets (i.e. different combinations of CPU
  flavor, OS, environment, etc.), you'd need to run &lt;code&gt;cargo-udeps&lt;/code&gt; on each of
  those to find per-target unused dependencies. For instance, if a dependency
  is only configured when compiling for x86_64 machines, then it may be flagged
  as unused on every other configuration.&lt;/li&gt;
&lt;li&gt;most of all, since it look at compilation artifacts, it cannot know if a
  specific dependency is directly used by your crate, or indirectly, leading to
  somehwat mystifying results in the case of workspaces.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let's dive a bit deeper into the last item, which I'll refer to as &lt;em&gt;the
transitively-used dependencies problem&lt;/em&gt;. Say you have your project &lt;code&gt;AAA&lt;/code&gt; that
contains a dependency to &lt;code&gt;serde&lt;/code&gt; in its &lt;code&gt;Cargo.toml&lt;/code&gt; file, while it's not
directly used by your code. In fact, if you did a text-search of &lt;code&gt;serde&lt;/code&gt; in
&lt;code&gt;AAA&lt;/code&gt;'s code with &lt;code&gt;grep&lt;/code&gt;, you wouldn't find a single match&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;1&lt;/a&gt;&lt;/sup&gt;. But now &lt;code&gt;AAA&lt;/code&gt;
is using another crate, &lt;code&gt;AB&lt;/code&gt;, that itself depends on &lt;code&gt;serde&lt;/code&gt;. &lt;code&gt;cargo-udeps&lt;/code&gt;
will see that &lt;code&gt;serde&lt;/code&gt; is used &lt;em&gt;overall&lt;/em&gt;, so it cannot let you know that &lt;code&gt;AAA&lt;/code&gt;'s
&lt;code&gt;Cargo.toml&lt;/code&gt; file references an unused dependency to &lt;code&gt;serde&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Graph of crates containing one unused crate" src="https://bouvier.cc/img/2021-11-30_machete/cargo-machete 1 - unused.excalidraw.png"&gt;&lt;/p&gt;
&lt;p&gt;How is this a problem? After all, if the workspace uses &lt;code&gt;serde&lt;/code&gt; even
indirectly, then we &lt;em&gt;will&lt;/em&gt; have to compile it at some point, so it's not like
it's &lt;em&gt;really&lt;/em&gt; unused.&lt;/p&gt;
&lt;p&gt;First of all, the &lt;code&gt;AAA&lt;/code&gt; crate might be using a different version of &lt;code&gt;serde&lt;/code&gt;
than the &lt;code&gt;AB&lt;/code&gt; crate, and this could result in different copies of the same
crate in your workspace. Note there are other nice tools that automatically
detect this kind of situation (hi there
&lt;a href="https://github.com/EmbarkStudios/cargo-deny/"&gt;cargo-deny&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Second, the order in which crates are compiled has an impact on compilation
parallelism, and having unused dependencies may add spurious synchronization
points in the compilation graph. When a Rust crate gets compiled by Cargo,
Cargo proceeds in two phases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;first, it collects information so as to unlock the compilation of other
  crates further down the road that may depend on this particular one. I don't
  know precisely what it entails, but one can make educated guesses: parse the
  code, analyze which items are &lt;code&gt;pub&lt;/code&gt;lic, compute memory layouts for public
  types, collect type information and so on and so forth.&lt;/li&gt;
&lt;li&gt;then, it does the actual compilation: optimize and generate the actual
  machine code for that particular crate, that will be later linked with other
  artifacts to form the final executable program.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The advantage of this two-phases scheme is that once Cargo is done with phase 1
for a particular crate, it can kick off the same process for other crates up
the dependency tree, while it runs phase 2 concurrently. With a multi-core
machine as is the norm on desktop computers, it's almost certain that this will
bring speedups!&lt;/p&gt;
&lt;p&gt;For instance, consider the following &lt;code&gt;Cargo.toml&lt;/code&gt; file from our previous
example project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[dependencies]&lt;/span&gt;
&lt;span class="n"&gt;serde&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then a possible compilation graph could look like that:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Compilation graph showing phases" src="https://bouvier.cc/img/2021-11-30_machete/cargo-machete 2 - phases.excalidraw.png"&gt;&lt;/p&gt;
&lt;p&gt;In this case, &lt;code&gt;ab&lt;/code&gt; phase 1 can start as soon as &lt;code&gt;serde&lt;/code&gt; phase 1 has finished,
while &lt;code&gt;serde&lt;/code&gt;'s compilation phase 2 happens in the background.&lt;/p&gt;
&lt;p&gt;If you're interested in reducing the overall compile times of your Rust
project, I would strongly suggest to &lt;a href="https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#timings"&gt;go read Rust's documentation around
timings
visualization&lt;/a&gt;.
Crates which spend lots of time in the first phase (or more generally, in both
phases) are basically pipelining bottlenecks, so identifying/removing/working
around them overall speeds up compile times.&lt;/p&gt;
&lt;p&gt;Back to our small unused dependency problem: an unused dependency in your
&lt;code&gt;Cargo.toml&lt;/code&gt; may block the compilation of other crates up the dependency tree,
and thus may slow down the whole compilation process by creating useless check
points.&lt;/p&gt;
&lt;p&gt;Consider a crate &lt;code&gt;C&lt;/code&gt; that depends on crates &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt;, with &lt;code&gt;B&lt;/code&gt; actually
unused:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Pipeline stall" src="https://bouvier.cc/img/2021-11-30_machete/cargo-machete 3 - pipeline stall.excalidraw.png"&gt;&lt;/p&gt;
&lt;p&gt;Here, the compilation of the crate &lt;code&gt;C&lt;/code&gt; could start way earlier, but it's
blocking waiting for the compilation of &lt;code&gt;B&lt;/code&gt; to finish first, while it's not
even used!&lt;/p&gt;
&lt;h2 id="solving-this-the-naive-way"&gt;&lt;a class="toclink" href="#solving-this-the-naive-way"&gt;Solving this, the naive way&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So when I was trying to confirm whether crates found by &lt;code&gt;cargo-udeps&lt;/code&gt; were
actually used or not in my Rust projects, the thing I'd do would be to &lt;code&gt;grep&lt;/code&gt;
(or better, use the blazingly fast Rust replacement
&lt;a href="https://github.com/BurntSushi/ripgrep"&gt;ripgrep&lt;/a&gt;) the crate's name in the
project. After all, the crate's name is in the source directory, if and only if
the crate is used, right?&lt;/p&gt;
&lt;p&gt;The answer is... mostly, yes. If we exclude dynamic code loading via mechanisms
like &lt;code&gt;dlopen&lt;/code&gt; or WebAssembly, then there aren't so many ways to use other
crates &lt;em&gt;directly&lt;/em&gt;, in Rust code. In fact, we can exhaustively enumerate all the
syntax items to use other dependencies in Rust:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my_crate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;your_crate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my_crate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;your_crate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my_crate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;my_crate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;my_crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;something&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I've looked at a bit of Rust code now, and I haven't seen other direct forms;
if I am missing any, please let me know! Now, these are the most &lt;em&gt;frequent&lt;/em&gt;
ways to use a dependency, but there are in fact other ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;build.rs&lt;/code&gt; scripts can generate code that could use other crates, and that
  would not be visible through a text search in the &lt;code&gt;src/&lt;/code&gt; directory, as the
  generated code is somewhere inside the &lt;code&gt;target/build/&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;macros (procedural or not) can expand to code that's using other crates,
  while the source code doesn't &lt;em&gt;explicitly&lt;/em&gt; mention them. For instance, the
  &lt;a href="https://github.com/Luthaf/log-once"&gt;&lt;code&gt;log_once&lt;/code&gt;&lt;/a&gt; crate uses the &lt;code&gt;log&lt;/code&gt; macros
  in its own macros, but &lt;code&gt;log_once&lt;/code&gt; doesn't depend on &lt;code&gt;log&lt;/code&gt; explicitly. It's a
  bold and smart move: it breaks the coupling with the specific version of
  &lt;code&gt;log&lt;/code&gt; , and as long as the high-level API of &lt;code&gt;log&lt;/code&gt; is stable (which is the
  case), then &lt;code&gt;log_once&lt;/code&gt; works with &lt;em&gt;any&lt;/em&gt; version of &lt;code&gt;log&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And then, there's still a bit of room for some false positives:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;raw text submatches: e.g. if a crate is named &lt;code&gt;bar&lt;/code&gt;, then &lt;code&gt;foobar::&lt;/code&gt; would be
  a match if we're doing a raw &lt;code&gt;grep&lt;/code&gt; search&lt;/li&gt;
&lt;li&gt;text search isn't syntaxic analysis, and we wouldn't know if a match is in a
  comment (&lt;code&gt;// use foo;&lt;/code&gt;), or a string (&lt;code&gt;String::from("use foo;")&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But that would do &lt;em&gt;most of the job&lt;/em&gt;, wouldn't it? In particular, compared to
&lt;code&gt;cargo-udeps&lt;/code&gt;, this approach doesn't suffer from the &lt;em&gt;transitively-used
dependencies&lt;/em&gt; problem. If you look for a crate's name in the &lt;code&gt;src/&lt;/code&gt; directory
and it's not there, it's likely not used by your crate. The End.&lt;/p&gt;
&lt;h2 id="a-tedious-process-calls-for-automation-so-i-made-a-tool"&gt;&lt;a class="toclink" href="#a-tedious-process-calls-for-automation-so-i-made-a-tool"&gt;A tedious process calls for automation, so I made a tool&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;And I've called it &lt;code&gt;cargo-machete&lt;/code&gt;. Like a machete, it is very useful for
quickly weeding out things, but it is very imprecise and you wouldn't trust it
at 100%.&lt;/p&gt;
&lt;p&gt;The gist of it is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;find directories that might contain Rust projects, as indicated by the
  presence of a &lt;code&gt;Cargo.toml&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;for each dependency, create an absolutely ugly regular expression that
  matches any of the syntaxic forms presented above. The regular expression
  does better than just raw text search, in particular it doesn't run into the
  text submatch issue.&lt;ul&gt;
&lt;li&gt;then for each file in the project, try to match the regular expression
  against each line of any source file, and stop at the first successful
  match (which means the dependency &lt;em&gt;is&lt;/em&gt; used)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This tool is &lt;em&gt;fast&lt;/em&gt;, because it combines the core library behind &lt;code&gt;ripgrep&lt;/code&gt; for
matching regular expressions, with &lt;em&gt;rayon&lt;/em&gt; for running it in parallel across
all the dependencies of a project. On my machine, the problem is CPU-bound,
because of the execution of the regular expression (and maybe thanks to my NVME
storage too). That's only one data point, but on this particular beefy desktop
I use, it scans the entirety of the &lt;code&gt;rust-lang/rust&lt;/code&gt; repository in 1.08
seconds, or all of &lt;code&gt;BytecodeAlliance/wasmtime&lt;/code&gt; in 0.58 seconds.&lt;/p&gt;
&lt;p&gt;The tool is &lt;a href="https://github.com/bnjbvr/cargo-machete"&gt;&lt;em&gt;open source&lt;/em&gt;&lt;/a&gt;, of course.&lt;/p&gt;
&lt;p&gt;As is the tradition for Cargo tools, it can be installed with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;cargo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cargo&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;machete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and then can be used, from any directory that contains Rust code (be it a
workspace, a single project, or a directory on top of many Rust projects), with
the following line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;cargo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;machete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here's an output example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;cargo&lt;span class="w"&gt; &lt;/span&gt;machete
Looking&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;crates&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;this&lt;span class="w"&gt; &lt;/span&gt;directory&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;analyzing&lt;span class="w"&gt; &lt;/span&gt;their&lt;span class="w"&gt; &lt;/span&gt;dependencies...
/home/ben/code/cargo-machete/integration-tests/with-bench/Cargo.toml&lt;span class="w"&gt; &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;no&lt;span class="w"&gt; &lt;/span&gt;package,&lt;span class="w"&gt; &lt;/span&gt;must&lt;span class="w"&gt; &lt;/span&gt;be&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;workspace
just-unused&lt;span class="w"&gt; &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;/home/ben/code/cargo-machete/integration-tests/just-unused/Cargo.toml:
&lt;span class="w"&gt;    &lt;/span&gt;log
unused-transitive&lt;span class="w"&gt; &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;/home/ben/code/cargo-machete/integration-tests/unused-transitive/Cargo.toml:
&lt;span class="w"&gt;    &lt;/span&gt;lib1
Done!
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are &lt;em&gt;false positives&lt;/em&gt;: code generated via macros or build scripts aren't
inspected as they're not in the &lt;code&gt;src/&lt;/code&gt; directory and &lt;code&gt;cargo-machete&lt;/code&gt; doesn't
run any compile step. For instance, if a project depends on &lt;code&gt;log&lt;/code&gt; , but uses it
only through &lt;code&gt;log_once&lt;/code&gt;, then &lt;code&gt;cargo-machete&lt;/code&gt; will incorrectly flag &lt;code&gt;log&lt;/code&gt; as an
unused dependency.&lt;/p&gt;
&lt;p&gt;The good news is that, thanks to a contribution from &lt;code&gt;@daniel5151&lt;/code&gt;, you can
specify &lt;em&gt;known false positives&lt;/em&gt; in the &lt;code&gt;Cargo.toml&lt;/code&gt; file of your crate,
allowing use of &lt;code&gt;cargo-machete&lt;/code&gt; in CI setups:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[package.metadata.cargo-machete]&lt;/span&gt;
&lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;log&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# false positive, used by log_once! macro&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As far as I know, the risk for &lt;em&gt;false negatives&lt;/em&gt; (i.e. crates that are unused,
but the tool thinks they're used) is pretty low. One such instance would be a
multi-line string containing one of the &lt;code&gt;use&lt;/code&gt; forms, but that seems rather
unlikely to be present in most Rust projects.&lt;/p&gt;
&lt;p&gt;The tool is still a bit rough, but it's been already quite useful for some
projects I've been working on! In a particular work project, most unused
dependencies were transitively used and compiled, but the rejiggering of the
compilation graph lead to a 5% compile time speedup overall. Good impact over
effort ratio.&lt;/p&gt;
&lt;h2 id="what-about-other-languages"&gt;&lt;a class="toclink" href="#what-about-other-languages"&gt;What about other languages?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What makes this possible in Rust, and could it be extended to other languages?&lt;/p&gt;
&lt;p&gt;Dynamic languages by nature dynamically load code, but there are still ways to
try to automate detecting unused dependencies same as &lt;code&gt;cargo-machete&lt;/code&gt; does.
Consider JavaScript and its &lt;code&gt;require&lt;/code&gt; function, that can dynamically evaluate a
string that's a path to a file with code we want to import. Since there's an
infinity of ways to create a string, we can't just perfectly rely on finding
&lt;code&gt;require("abc")&lt;/code&gt; and assume that if not present, then &lt;code&gt;abc&lt;/code&gt; isn't used. Ditto
with &lt;code&gt;import&lt;/code&gt; statements, which can evaluate dynamic sources. That being said,
if JS code is restricted to use &lt;code&gt;require&lt;/code&gt; statements with only static strings
or static &lt;code&gt;import&lt;/code&gt; statements, then this may work too! Although when
restricting to static &lt;code&gt;require&lt;/code&gt;s, even just &lt;em&gt;loading&lt;/em&gt; the code in NodeJS would
be sufficient to find unused dependencies with perfect accuraccy.&lt;/p&gt;
&lt;p&gt;Back to static languages, where I constrain the problem to non-dynamic
dependencies (loaded via &lt;code&gt;dlopen&lt;/code&gt; etc.). In a language like C or C++, there are
no unified module systems or package description (yet! although &lt;code&gt;cmake&lt;/code&gt; might
be a de-facto standard). We can still apply this to header files, and look for
their inclusion via &lt;code&gt;#include&lt;/code&gt; statements. Macros and preprocessed code would
also throw a wrench in the process. Then some human intervention would still be
required to eliminate the .c files, but I haven't thought about it too much.&lt;/p&gt;
&lt;p&gt;Static analysis of compiled binaries might be simpler, for that matter. If we
consider the problem for WebAssembly, we can frame it as "which imported
functions are not used in the module", potentially eliminating an entire range
of host functions. In the simplest case, we could just look at the code
section, through the function bodies, and see if there's any reference to
indices of every single imported function in &lt;code&gt;call&lt;/code&gt; opcodes. Then, there can be
function &lt;code&gt;Table&lt;/code&gt;s referencing those, so we have to make sure no table elements
reference the function. And if any table is mutable and publicly exposed via an
export, then a user of the wasm module may reference any function declared in
the wasm module, including imported functions, so all bets are off. Note
dead-code elimination in wasm would be pretty similar and suffer from the same
limitations: after all, a function dependency is just another kind of function,
in wasm! Each format may have such idiosyncrasies like that. Static analysis of
final binaries (as opposed to libraries) might be possible and reliable,
though.&lt;/p&gt;
&lt;h2 id="closing-thoughts"&gt;&lt;a class="toclink" href="#closing-thoughts"&gt;Closing thoughts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For the sake of completeness, I should mention the existence of a rustc
crate-wide lint for this, &lt;a href="https://github.com/rust-lang/rust/pull/72342"&gt;since May 2020 or
so&lt;/a&gt;:
&lt;code&gt;#![warn(unused_crate_dependencies)]&lt;/code&gt;. This tells about unused crate
dependencies directly as a Rust warning, which in my opinion would be the ideal
end goal! Unfortunately, some Github comments suggest it suffers from having
too many false positives, and still it requires compiling the code.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@est31&lt;/code&gt;, of &lt;code&gt;cargo-udeps&lt;/code&gt;'s fame, has been working on a &lt;a href="https://github.com/rust-lang/cargo/pull/8437"&gt;better
solution&lt;/a&gt;. It seems to not be so
far from completion, so between this and the Rust lint, I'm hopeful that there
could be a time where we have a solution that is perfectly precise, with
neither false positives nor false negatives.&lt;/p&gt;
&lt;p&gt;In the meanwhile, I hope that &lt;code&gt;cargo-machete&lt;/code&gt; can be useful to some of you, or
that it inspires others to make similar quick-and-dirty tools, in Rust or in
other languages. Thanks for reading this far, and please &lt;a href="@mailto:benjamin+cargomachete@bouvier.cc"&gt;get in
touch&lt;/a&gt; if you have any thoughts about this!&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Wait for it...&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;If you don't know about the &lt;code&gt;cargo-edit&lt;/code&gt; tool that allows you to add a
  dependency in one line with &lt;code&gt;cargo add serde&lt;/code&gt; to your project: &lt;a href="https://github.com/killercup/cargo-edit"&gt;now you
  do&lt;/a&gt;.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Wed, 27 Apr 2022 23:17:23 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2022-04-27:/cargo-machete/</guid><category>blog</category></item><item><title>A primer on code generation in Cranelift</title><link>https://bouvier.cc/cranelift-codegen-primer/</link><description>&lt;p&gt;&lt;a href="https://github.com/bytecodealliance/wasmtime/tree/main/cranelift#cranelift-code-generator"&gt;Cranelift&lt;/a&gt; is a code generator written in the Rust programming language that aims to be a fast code generator, which outputs machine code that runs at reasonable speeds.&lt;/p&gt;
&lt;p&gt;The Cranelift compilation model consists in compiling functions one by one, holding extra information about external entities, like external functions, memory addresses, and so on. This model allows for concurrent and parallel compilation of individual functions, which supports the goal of fast compilation. It was designed this way to allow for just-in-time (JIT) compilation of WebAssembly binary code in Firefox, although its scope has broadened a bit. Nowadays it is used in a few different WebAssembly runtimes, including &lt;a href="https://github.com/bytecodealliance/wasmtime#wasmtime"&gt;Wasmtime&lt;/a&gt; and &lt;a href="https://wasmer.io/"&gt;Wasmer&lt;/a&gt;, but also as an alternative backend for Rust debug compilation, thanks to &lt;a href="https://github.com/bjorn3/rustc_codegen_cranelift"&gt;cg_clif&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;A classic compiler design usually includes running a parser to translate the source to some form of intermediate representations, then run optimization passes onto them, then feeds this to the machine code generator.&lt;/p&gt;
&lt;p&gt;This blog post focuses on the final step, namely the concepts that are involved in code generation, and what they map to in Cranelift. To make things more concrete, we'll take a specific instruction, and see how it's translated, from its creation down to code generation. At each step of the process, I'll provide a short (&lt;em&gt;ahem&lt;/em&gt;) high-level explanation of the concepts involved, and I'll show what they map to in Cranelift, using the example instruction. While this is not a tutorial detailing how to add new instructions in Cranelift, this should be an interesting read for anyone who's interested in compilers, and this could be an entry point if you're interested in hacking on the Cranelift &lt;code&gt;codegen&lt;/code&gt; crate.&lt;/p&gt;
&lt;p&gt;This is our plan for this blog post: each squared box represents data, each
rounded box is a process. We're going to go through each of them below.&lt;/p&gt;
&lt;div class="mermaid"&gt;
graph TD;
    clif[Optimized CLIF];
    vcode[VCode];
    final_vcode[Final VCode];
    machine_code[Machine code artifacts];
    lowering([Lowering]);
    regalloc([Register allocation]);
    codegen([Machine code generation]);
    clif --&gt; lowering --&gt; vcode --&gt; regalloc --&gt; final_vcode --&gt; codegen --&gt; machine_code
&lt;/div&gt;

&lt;h2 id="intermediate-representations"&gt;&lt;a class="toclink" href="#intermediate-representations"&gt;Intermediate representations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Compilers use &lt;strong&gt;intermediate representations&lt;/strong&gt; (&lt;em&gt;IR&lt;/em&gt;) to represent source code. Here we're interested in representations of the &lt;em&gt;data flow&lt;/em&gt;, that is instructions themselves and only that. The IRs contain information about the instructions themselves, their operands, type specialization information, and any additional metadata that might be useful. IRs usually map to a certain level of abstraction, and as such, they are useful for solving different problems that require different levels of abstraction. Their shape (which data structures) and numbers often have a huge impact on the performance of the compiler itself (that is, how fast it is at compiling).&lt;/p&gt;
&lt;p&gt;In general, most programming languages use IRs internally, and yet, these are invisible to the programmers. The reason is that source code is usually first &lt;em&gt;parsed&lt;/em&gt; (tokenized, verified) and then translated into an IR. The &lt;em&gt;abstract syntax tree&lt;/em&gt;, aka AST, is one such IR representing the source code itself, in a format that's very close to the source code itself. Since the raison d'être of Cranelift is to be a code generator, having a text format is secondary, and only useful for testing and debugging purposes. That's why embedders directly create and manipulate Cranelift's IR.&lt;/p&gt;
&lt;p&gt;At the time of writing, Cranelift has two IRs to represent the function's code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;one external, high-level intermediate representation, called &lt;strong&gt;CLIF&lt;/strong&gt; (for &lt;em&gt;Cranelift IR format&lt;/em&gt;),&lt;/li&gt;
&lt;li&gt;one internal, low-level intermediate representation called &lt;strong&gt;VCode&lt;/strong&gt; (for &lt;em&gt;virtual-registerized code&lt;/em&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="clif-ir"&gt;&lt;a class="toclink" href="#clif-ir"&gt;CLIF IR&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CLIF is the IR that Cranelift embedders create and manipulate. It consists of high-level typed operations that are convenient to use and/or can be simply translated to machine code. It is in &lt;a href="https://en.wikipedia.org/wiki/Static_single_assignment_form"&gt;static single assignment (SSA) form&lt;/a&gt;: each value referenced by an operation (SSA value) is defined only once, and may have as many uses as desired. CLIF is practical to use and manipulate for classic compilers optimization passes (e.g. &lt;a href="https://en.wikipedia.org/wiki/Loop-invariant_code_motion"&gt;LICM&lt;/a&gt;), as it is generic over the target architecture which we're compiling to.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ins&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;iconst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;I64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ins&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;iconst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;I64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1337&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ins&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;iadd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;An example of Rust code that would generate CLIF IR: using an IR builder, two constant 64-bits integer SSA values x and y are created, and then added together. The result is stored into the &lt;code&gt;sum&lt;/code&gt; SSA value, which can then be consumed by other instructions.&lt;/p&gt;
&lt;p&gt;The code for the IR builder we're manipulating above is automatically generated by the &lt;code&gt;cranelift-codegen&lt;/code&gt; build script. The build script uses a domain specific &lt;em&gt;meta&lt;/em&gt; language (DSL)&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;1&lt;/a&gt;&lt;/sup&gt; that defines the instructions, their input and output operands, which input types are allowed, how the output type is inferred, etc. We won't take a look at this &lt;em&gt;today&lt;/em&gt;: this is a bit too far from code generation, but this could be material for another blog post.&lt;/p&gt;
&lt;p&gt;As an example of a full-blown CLIF generator, there is &lt;a href="https://github.com/bytecodealliance/wasmtime/tree/main/cranelift/wasm"&gt;a crate&lt;/a&gt; in the Cranelift project that allows translating from the WebAssembly binary format to CLIF. The Cranelift backend for Rustc uses its own CLIF generator that translates from one of the Rust compiler's IRs.&lt;/p&gt;
&lt;p&gt;Finally, it's time to reveal what's going to be our running example! The Chosen One is the &lt;code&gt;iadd&lt;/code&gt; CLIF operation, which allows to add two integers of any length together, with wrapping semantics. It is both simple to understand what it does, and exhibits interesting behaviors on the two architectures we're interested in. So, let's continue down the pipeline!&lt;/p&gt;
&lt;h2 id="vcode-ir"&gt;&lt;a class="toclink" href="#vcode-ir"&gt;VCode IR&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Later on, the CLIF intermediate representation is &lt;em&gt;lowered&lt;/em&gt;, i.e. transformed from a high-level one into a lower-level one. Here lower level means a form more specialized for a machine architecture. This lower IR is called &lt;em&gt;VCode&lt;/em&gt; in Cranelift. The values it references are called &lt;em&gt;virtual registers&lt;/em&gt; (more on the &lt;em&gt;virtual&lt;/em&gt; bit below). They're not in SSA form anymore: each virtual register may be redefined as many times as we want. This IR is used to encode register allocation constraints and it guides machine code generation. As a matter of fact, since this information is tied to the machine code's representation itself, this IR is also target-specific: there's one flavor of VCode per each CPU architecture we're compiling to.&lt;/p&gt;
&lt;p&gt;Let's get back to our example, that we're going to compile on two instruction set architectures:
- ARM 64-bits (aka aarch64), which is used in most mobile devices but start to become mainstream on laptops (Apple's Mac M1, some Chromebooks)
- Intel's x86 64-bits (aka x86_64, also abbreviated x64), which is used in most desktop and laptop machines).&lt;/p&gt;
&lt;p&gt;An integer addition machine instruction on aarch64 will take three operands: two input operands (one of which must be a register), and another third output register operand. While on the x86_64 architecture, the equivalent instruction involves a total of two registers: one that is a read-only source register, and another that is an in-out modified register, containing both the second source and the destination register. We'll get back to this.&lt;/p&gt;
&lt;p&gt;So considering &lt;code&gt;iadd&lt;/code&gt;, let's look at (one of&lt;sup id="fnref:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;2&lt;/a&gt;&lt;/sup&gt;) the VCode instruction that's used to represent integer additions on aarch64 (as defined in &lt;code&gt;cranelift/codegen/src/isa/aarch64/inst/mod.rs&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="sd"&gt;/// An ALU operation with two register sources and a register destination.&lt;/span&gt;
&lt;span class="n"&gt;AluRRR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;alu_op&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ALUOp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Writable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Reg&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;rn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Reg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Reg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Some details here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;alu_op&lt;/code&gt; defines the sub-opcode used in the ALU (Arithmetic Logic Unit). It will be &lt;code&gt;AluOp::Add64&lt;/code&gt; for a 64-bits integer addition.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rn&lt;/code&gt; and &lt;code&gt;rm&lt;/code&gt; are the conventional aarch64 names for the two input registers.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rd&lt;/code&gt; is the destination register. See how it's marked as &lt;code&gt;Writable&lt;/code&gt;, while the two others are not? &lt;code&gt;Writable&lt;/code&gt; is a plain Rust wrapper that makes sure that we &lt;em&gt;can&lt;/em&gt; statically differentiate read-only registers from writable registers; a neat trick that allows us to catch more issues at compile-time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All this information is directly tied to the machine code representation of an addition instruction on aarch64: each field is later used to select some bytes that will be generated during code generation.&lt;/p&gt;
&lt;p&gt;As said before, the VCode is specific to each architecture, so x86_64 has a different VCode representation for the same instruction (as defined in &lt;code&gt;cranelift/codegen/src/isa/x64/inst/mod.rs&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="sd"&gt;/// Integer arithmetic/bit-twiddling: (add sub and or xor mul adc? sbb?) (32 64) (reg addr imm) reg&lt;/span&gt;
&lt;span class="n"&gt;AluRmiR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;is_64&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;AluRmiROpcode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;RegMemImm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Writable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Reg&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, the sub-opcode is defined as part of the &lt;code&gt;AluRmiROpcode&lt;/code&gt; enum (the comment hints at which other x86 machine instructions are generated by this same VCode). See how there's only one &lt;code&gt;src&lt;/code&gt; (source) register (or memory or immediate operand), while the instruction conceptually takes two inputs? That's because it's expected that the &lt;code&gt;dst&lt;/code&gt; (destination) register is &lt;em&gt;modified&lt;/em&gt;, that is, both read (so it's the second input operand) and written to (so it's the result register). In equivalent C code, the x86's add instruction doesn't actually do &lt;code&gt;a = b + c&lt;/code&gt;. What it does is &lt;code&gt;a += b&lt;/code&gt;, that is, one of the sources is &lt;em&gt;consumed&lt;/em&gt; by the instruction. This is an artifact inherited from the design of older x86 machines in the 1970's, when instructions were designed around an accumulator model (and representing efficiently three operands in a CISC architecture would make the encoding larger and harder than it is).&lt;/p&gt;
&lt;h2 id="instruction-selection-lowering"&gt;&lt;a class="toclink" href="#instruction-selection-lowering"&gt;Instruction selection (lowering)&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As said before, converting from the high-level IR (CLIF) to the low-level IR (VCode) is called lowering. Since VCode is target-dependent, this process is also target-dependent. That's where we consider which machine instructions get eventually used for a given CLIF opcode. There are many ways to achieve the same machine state results for given semantics, but some of these ways are faster than other, and/or require fewer code bytes to achieve. The problem can be summed up like this: given some CLIF, which VCode can we create to generate the fastest and/or smallest machine code that carries out the desired semantics? This is called &lt;em&gt;instruction selection&lt;/em&gt;, because we're selecting the VCode instructions among a set of different possible instructions.&lt;/p&gt;
&lt;p&gt;How do these IR map to each other? A given CLIF node may be lowered into 1 to N VCode instructions. A given VCode instruction may lead to the code generation of 1 to M machine instructions. There are no rules governing the maximum of entities mapped. For instance, the integer addition CLIF opcode &lt;code&gt;iadd&lt;/code&gt; on 64-bits inputs maps to a single VCode instruction on aarch64. The VCode instruction then causes a single code instruction to be generated.&lt;/p&gt;
&lt;p&gt;Other CLIF opcodes may generate more than a single machine instruction eventually. Consider the CLIF opcode for signed integer division &lt;code&gt;idiv&lt;/code&gt;. Its semantics define that it traps for zero inputs and in case of integer overflow&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;. On aarch64, this is lowered into:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;one VCode instruction that checks if the input is zero and trap otherwise&lt;/li&gt;
&lt;li&gt;two VCode instructions for comparing the input values against the minimal integer value and -1&lt;/li&gt;
&lt;li&gt;one VCode instruction to trap if the two input values match what we checked against&lt;/li&gt;
&lt;li&gt;and one VCode instruction that does the actual division operation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these VCode instruction then generates one or more machine code instructions, resulting in a bit of a longer sequence.&lt;/p&gt;
&lt;p&gt;Let's look at the lowering of &lt;code&gt;iadd&lt;/code&gt; on aarch64 (in &lt;code&gt;cranelift/codegen/src/isa/aarch64/lower_inst.rs&lt;/code&gt;), edited and simplified for clarity. I've added comments in the code, explaining what each line does:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Opcode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Iadd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Get the destination register.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_output_reg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="n"&gt;only_reg&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Get the controlling type of the addition (32-bits int or 64-bits int or&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// int vector, etc.).&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Force one of the inputs into a register, not applying any signed- or&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// zero-extension.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;put_input_in_reg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NarrowValueMode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Try to see if we can encode the second operand as an immediate on&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// 12-bits, maybe by negating it;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Otherwise, put it into a register.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;negated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;put_input_in_rse_imm12_maybe_negated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ty_bits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;NarrowValueMode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Select the ALU subopcode, based on possible negation and controlling&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// type.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alu_op&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;negated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;choose_32_64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ALUOp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Add32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ALUOp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Add64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;choose_32_64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ty&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ALUOp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Sub32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ALUOp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Sub64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Emit the VCode instruction in the VCode stream.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alu_inst_imm12&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;alu_op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In fact, the &lt;code&gt;alu_inst_imm12&lt;/code&gt; wrapper can create one VCode instruction among a set of possible ones (since we're trying to select &lt;em&gt;the best one&lt;/em&gt;). For the sake of simplicity, we'll assume that &lt;code&gt;AluRRR&lt;/code&gt; is going to be generated, i.e. the selected instruction is the one using only register encodings for the input values.&lt;/p&gt;
&lt;h2 id="register-allocation"&gt;&lt;a class="toclink" href="#register-allocation"&gt;Register allocation&lt;/a&gt;&lt;/h2&gt;
&lt;div class="mermaid"&gt;
graph TD
    vcode_vreg[VCode with virtual registers]
    regalloc([Register allocation])
    vcode_rreg[VCode with real registers]
    codegen([Code generation])
    machine_code(Machine code)
    vcode_vreg --&gt; regalloc --&gt; vcode_rreg --&gt; codegen --&gt; machine_code
&lt;/div&gt;

&lt;h3 id="vcode-registers-and-stack-slots"&gt;&lt;a class="toclink" href="#vcode-registers-and-stack-slots"&gt;VCode, registers and stack slots&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Hey, ever wondered what the V in VCode meant? Back to the drawing board. While a program may reference a theoretically unlimited number of instructions, each referencing a theoretically unlimited number of values as inputs and outputs, the physical machine only has a fixed set of containers for those values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;either they must live in machine &lt;strong&gt;registers&lt;/strong&gt;: very fast to access in the CPU, take some CPU real estate, thus are costly, so there are usually few of them.&lt;/li&gt;
&lt;li&gt;or they must live in the process' &lt;strong&gt;stack memory&lt;/strong&gt;: it's slower to access, but we can have virtually any amount of stack &lt;em&gt;slots&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%edi&lt;/span&gt;&lt;span class="p"&gt;,-&lt;/span&gt;&lt;span class="mi"&gt;0x4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;%rbp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;%rsi&lt;/span&gt;&lt;span class="p"&gt;,-&lt;/span&gt;&lt;span class="mi"&gt;0x10&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;%rbp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;mov&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-0&lt;/span&gt;&lt;span class="no"&gt;x4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;%rbp&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="nv"&gt;%eax&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;In this example of x86 machine code, %edi, %rsi, %rbp, %eax are all registers; stack slots are memory addresses computed as the frame pointer (%rbp) plus an offset value (which happens to be negative here). Note that stack slots may be referred to by the stack pointer (%rsp) in general.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="defining-the-register-allocation-problem"&gt;&lt;a class="toclink" href="#defining-the-register-allocation-problem"&gt;Defining the register allocation problem&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The problem of mapping the IR values (in VCode these are the &lt;code&gt;Reg&lt;/code&gt;) to machine "containers" is called &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Register_allocation"&gt;register allocation&lt;/a&gt;&lt;/strong&gt; (aka regalloc). Inputs to register allocation can be as numerous as we want them, and map to "virtual" values, hence we call them &lt;em&gt;virtual registers&lt;/em&gt;. And... that's where the V from VCode comes from: the instructions in VCode reference values that are &lt;em&gt;virtual&lt;/em&gt; registers before register allocation, so we say the code is in &lt;em&gt;virtualized&lt;/em&gt; register form. The output of register allocation is a set of new instructions, where the virtual registers have been replaced by &lt;em&gt;real registers&lt;/em&gt; (the physical ones, limited in quantity) or stack slots references (and other additional metadata).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before register allocation, with unlimited virtual registers:&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;
&lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;v4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="n"&gt;v5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v3&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v5&lt;/span&gt;

&lt;span class="c1"&gt;// One possible register allocation, on a machine that has 2 registers %r0, %r1:&lt;/span&gt;
&lt;span class="nf"&gt;%r0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r1&lt;/span&gt;
&lt;span class="nf"&gt;%r1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="nf"&gt;%r0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="nf"&gt;%r1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r1&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When all is well, the virtual registers don't conceptually &lt;em&gt;live&lt;/em&gt; at the same time, and they can be put into physical registers. Issues arise when there's not enough physical registers to contain all the virtual registers that live at the same time, which is the case for... a very large majority of programs. Then, register allocation must decide which registers continue to live in registers at a given program point, and which should be &lt;strong&gt;spilled&lt;/strong&gt; into a stack slot, effectively &lt;em&gt;storing&lt;/em&gt; them onto the stack for later use. This later reuse will imply to &lt;strong&gt;reload&lt;/strong&gt; them from the stack slot, using a &lt;em&gt;load&lt;/em&gt; machine instruction. The complexity resides in choosing which registers should be spilled, at which program point they should be spilled, and at which program points we should reload them, if we need to do so. Making good choices there will have a large impact on the speed of the generated code, since memory accesses to the stack imply an additional runtime cost. For instance, a variable that's frequently used in a hot loop should live in a register for the whole loop's lifetime, and not be spilled/reloaded in the middle of the loop.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before register allocation, with unlimited virtual registers:&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;
&lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v2&lt;/span&gt;
&lt;span class="n"&gt;v4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v4&lt;/span&gt;

&lt;span class="c1"&gt;// One possible register allocation, on a machine that has 2 registers %r0, %r1.&lt;/span&gt;
&lt;span class="c1"&gt;// We need to spill one value, because there&amp;#39;s a point where 3 values are live at the same time!&lt;/span&gt;
&lt;span class="n"&gt;spill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stack_slot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;%r1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r1&lt;/span&gt;
&lt;span class="nf"&gt;%r1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r1&lt;/span&gt;
&lt;span class="n"&gt;reload&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stack_slot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r0&lt;/span&gt;
&lt;span class="nf"&gt;%r1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r0&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And, since we like to have our cake and eat it too, the register allocator itself should be &lt;em&gt;fast&lt;/em&gt;: it should not take an unbounded amount of time to make these allocation decisions. Register allocation has the good taste to be a &lt;a href="https://en.wikipedia.org/wiki/NP-completeness"&gt;NP-complete&lt;/a&gt; problem. Concretely, this means that implementations cannot find the &lt;em&gt;best&lt;/em&gt; solutions given arbitrary inputs, but they'll estimate &lt;em&gt;good&lt;/em&gt; solutions based on heuristics, in worst-case quadratic time over the size of the input. All of this makes it so that register allocation has its own whole research field, and has been extensively studied for some time now. It is a fascinating problem.&lt;/p&gt;
&lt;h3 id="register-allocation-in-cranelift"&gt;&lt;a class="toclink" href="#register-allocation-in-cranelift"&gt;Register allocation in Cranelift&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Back to Cranelift. The register allocation contract is that if a value &lt;em&gt;must&lt;/em&gt; live in a real register at a given program point, then it &lt;em&gt;does&lt;/em&gt; live where it should (unless register allocation is impossible). At the start of code generation for a VCode instruction, we are guaranteed that the input values live in real registers, and that the output real register is available before the next VCode instruction.&lt;/p&gt;
&lt;p&gt;You might have noticed that the VCode instructions only refer to registers, and not stack slots. But where are the stack slots, then? The trick is that the stack slots are &lt;em&gt;invisible&lt;/em&gt; to VCode. Register allocation may create an arbitrary number of spills, reloads, and register moves&lt;sup id="fnref:5"&gt;&lt;a class="footnote-ref" href="#fn:5"&gt;4&lt;/a&gt;&lt;/sup&gt; around VCode instructions, to ensure that their register allocation constraints are met. This is why the output of register allocation is a new list of instructions, that includes not only the initial instructions filled with the actual registers, but also additional spill, reload and move (VCode) instructions added by regalloc.&lt;/p&gt;
&lt;p&gt;As said before, this problem is so sufficiently complex, involved and independent from the rest of the code (assuming the right set of interfaces!) that its code lives in a separate crate, &lt;a href="https://github.com/bytecodealliance/regalloc.rs"&gt;&lt;code&gt;regalloc.rs&lt;/code&gt;&lt;/a&gt;, with its own fuzzing and testing infrastructure. I hope to shed some light on it at some point too.&lt;/p&gt;
&lt;p&gt;What's interesting to us today is the register allocation &lt;em&gt;constraints&lt;/em&gt;. Consider the aarch64 integer add instruction &lt;code&gt;add rd, rn, rm&lt;/code&gt;: &lt;code&gt;rd&lt;/code&gt; is the output virtual register that's written to, while &lt;code&gt;rn&lt;/code&gt; and &lt;code&gt;rm&lt;/code&gt; are the inputs, thus read from. We need to inform the register allocation algorithm about these constraints. In regalloc jargon, "read to" is known as &lt;em&gt;used&lt;/em&gt;, while "written to" is known as &lt;em&gt;defined&lt;/em&gt;. Here, the aarch64 VCode instruction &lt;code&gt;AluRRR&lt;/code&gt; does &lt;em&gt;use&lt;/em&gt; &lt;code&gt;rn&lt;/code&gt; and &lt;code&gt;rm&lt;/code&gt;, and it &lt;em&gt;def&lt;/em&gt;ines &lt;code&gt;rd&lt;/code&gt;. This usage information is &lt;em&gt;collected&lt;/em&gt; in the &lt;code&gt;aarch64_get_regs&lt;/code&gt; function (&lt;code&gt;cranelift/codegen/src/isa/aarch64/inst/mod.rs&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;aarch64_get_regs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;Inst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;collector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RegUsageCollector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Inst&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AluRRR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;collector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_def&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;collector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;collector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// etc.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, after register allocation has assigned the physical registers, we need to instruct it how to replace virtual register mentions by physical register mentions. This is done in the &lt;code&gt;aarch64_map_regs&lt;/code&gt; function (same file as above):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;aarch64_map_regs&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RUM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;RegUsageMapper&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Inst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kp"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nc"&gt;RUM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Inst&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AluRRR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;map_def&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;map_use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;map_use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// etc.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note this is reflecting quite precisely what the usage collector did: we're replacing the virtual register mention for the defined register &lt;code&gt;rd&lt;/code&gt; with the information (which real register) provided by the &lt;code&gt;RegUsageMapper&lt;/code&gt;. These two functions must stay in sync, otherwise here be dragons! (and bugs very hard to debug!)&lt;/p&gt;
&lt;h3 id="register-allocation-on-x86"&gt;&lt;a class="toclink" href="#register-allocation-on-x86"&gt;Register allocation on x86&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On Intel's x86, register allocation may be a bit trickier: in some cases, the lowering needs to be carefully written so it satisfies some register allocation constraints that are very specific to this architecture. In particular, x86 has &lt;em&gt;fixed register constraints&lt;/em&gt; as well as &lt;em&gt;tied operands&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For this specific part, we'll look at the integer shift-left instruction, which is equivalent to C's &lt;code&gt;x &amp;lt;&amp;lt; y&lt;/code&gt;. Why this particular instruction? It exhibits both properties that we're interested in studying here. The lowering of &lt;code&gt;iadd&lt;/code&gt; is similar, albeit slightly simpler, as it &lt;em&gt;only&lt;/em&gt; involves tied operands.&lt;/p&gt;
&lt;h4 id="fixed-register-constraints"&gt;&lt;a class="toclink" href="#fixed-register-constraints"&gt;Fixed register constraints&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;On the one hand, some instructions expect their inputs to be in &lt;em&gt;fixed&lt;/em&gt; registers, that is, specific registers arbitrarily predefined by the architecture manual. For the example of the shift instruction, if the count is not statically known at compile time (it's not a shift by a constant value), then the amount by which we're shifting must be in the &lt;code&gt;rcx&lt;/code&gt; register&lt;sup id="fnref:8"&gt;&lt;a class="footnote-ref" href="#fn:8"&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;Now, how do we make sure that the input value actually is in &lt;code&gt;rcx&lt;/code&gt;? We can mark &lt;code&gt;rcx&lt;/code&gt; as used in the &lt;code&gt;get_regs&lt;/code&gt; function so regalloc knows about this, but nothing ensures that the input &lt;em&gt;resides&lt;/em&gt; in it at the beginning of the instruction. To resolve this, we'll introduce a &lt;strong&gt;move instruction&lt;/strong&gt; during lowering, that is going to copy the input value into &lt;code&gt;rcx&lt;/code&gt;. Then we're sure it lives there, and register allocation knows it's used: we're good to go!&lt;/p&gt;
&lt;p&gt;In a nutshell, this shows how lowering and register allocation play together:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;during lowering, we introduce a move from a dynamic shift input value to &lt;code&gt;rcx&lt;/code&gt; before the actual shift&lt;/li&gt;
&lt;li&gt;in the register usage function, we mark &lt;code&gt;rcx&lt;/code&gt; as used&lt;/li&gt;
&lt;li&gt;(nothing to do in the register mapping function: &lt;code&gt;rcx&lt;/code&gt; is a real register already)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="tied-operands"&gt;&lt;a class="toclink" href="#tied-operands"&gt;Tied operands&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;On the other hand, some instructions have operands that are both read and written at the same time: we call them &lt;em&gt;modified&lt;/em&gt; in Cranelift and regalloc.rs, but they're also known as &lt;em&gt;tied operands&lt;/em&gt; in the compiler literature. It's not just that there's a register that must be read, and a register that must be written to: they &lt;em&gt;must&lt;/em&gt; be the same register. How do we model this, then?&lt;/p&gt;
&lt;p&gt;Consider a naive solution. We take the input virtual register, and decide it's allocated to the same register as the output (modified) register. Unfortunately, if the chosen virtual register was going to be reused by another later VCode instruction, then its value would be overwritten (clobbered) by the current instruction. This would result in incorrect code being generated, so this is not acceptable. In general we can't clobber the value that was in an input value during lowering, because that's the role of regalloc to make this kind of decisions.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before register allocation, with virtual registers:&lt;/span&gt;
&lt;span class="n"&gt;v2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;
&lt;span class="n"&gt;v3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;

&lt;span class="c1"&gt;// After register allocation, on a machine with two registers %r0 and %r1:&lt;/span&gt;
&lt;span class="c1"&gt;// assign v0 to %r0, v1 to %r1, v2 to %r0&lt;/span&gt;
&lt;span class="nf"&gt;%r0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;%r0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// ohnoes! the value in %r0 is v2, not v0 anymore!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The right solution is, again, to &lt;em&gt;copy&lt;/em&gt; this input virtual register into the output virtual register, right before the instruction. This way, we can still reuse the untouched input register in other instructions without modifying it: only the copy is written to.&lt;/p&gt;
&lt;p&gt;Pfew! We can now look at the entire lowering for the shift left instruction, edited and commented for clarity:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Read the instruction operand size from the output&amp;#39;s type.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dst_ty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Put the left hand side into a virtual register.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lhs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;put_input_in_reg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;// Put the right hand side (shift amount) into either an immediate (if it&amp;#39;s&lt;/span&gt;
&lt;span class="c1"&gt;// statically known at compile time), or into a virtual register.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rhs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_input_as_source_or_const&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;insn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;constant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Mask count, according to Cranelift&amp;#39;s semantics.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dst_ty&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bits&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u8&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cst&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;put_input_in_reg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Get the destination virtual register.&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_output_reg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="n"&gt;only_reg&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Copy the left hand side into the (modified) output operand, to satisfy the&lt;/span&gt;
&lt;span class="c1"&gt;// mod constraint.&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Inst&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mov_r_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lhs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// If the shift count is statically known: nothing particular to do. Otherwise,&lt;/span&gt;
&lt;span class="c1"&gt;// we need to put it in the RCX register.&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_none&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;w_rcx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Writable&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;from_reg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;rcx&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Copy the shift count (which is in rhs) into RCX.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Inst&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mov_r_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rhs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unwrap&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;w_rcx&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Generate the actual shift instruction.&lt;/span&gt;
&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Inst&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;shift_r&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ShiftKind&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ShiftLeft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And this is how we tell the register usage collector about our constraints:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Inst&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ShiftR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num_bits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;num_bits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_none&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// if the shift count is dynamic, mark RCX as used.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;collector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regs&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;rcx&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// In all the cases, the destination operand is modified.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;collector&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Only the modified register needs to be mapped to its allocated physical register:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Inst&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ShiftR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;map_mod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="virtual-registers-copies-and-performance"&gt;&lt;a class="toclink" href="#virtual-registers-copies-and-performance"&gt;Virtual registers copies and performance&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Do these virtual register copies sound costly to you? In theory, they could lead to the code generation of a move instructions, increasing the size of the code generated and causing a small runtime cost. In practice, 
register allocation, through its interface, knows how to identify move instructions, their source and their destination. By analyzing them, it can see when a source isn't used after a given move instruction, and thus allocate the same register for the source and the destination of the move. Then, when Cranelift generates the code, it will avoid generating a move from a physical register to the same one&lt;sup id="fnref:7"&gt;&lt;a class="footnote-ref" href="#fn:7"&gt;6&lt;/a&gt;&lt;/sup&gt;. As a matter of fact, creating a VCode copy doesn't necessarily mean that it will generate a machine code move instruction later: it is present just in case regalloc &lt;em&gt;needs&lt;/em&gt; it, but it can be avoided when it's spurious.&lt;/p&gt;
&lt;h2 id="code-generation"&gt;&lt;a class="toclink" href="#code-generation"&gt;Code generation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Oh my, we're getting closer to actually being able to run the code! Once register allocation has run, we can generate the actual machine code for the VCode instructions. Cool kids call this step of the pipeline &lt;em&gt;codegen&lt;/em&gt;, for code generation. This is the part where we decipher the architecture manuals provided by the CPU vendors, and generate the raw machine bytes for our machine instructions. In Cranelift, this means filling a code buffer (there's a &lt;code&gt;MachBuffer&lt;/code&gt; sink interface for this!), returned along some internal relocations&lt;sup id="fnref:6"&gt;&lt;a class="footnote-ref" href="#fn:6"&gt;7&lt;/a&gt;&lt;/sup&gt; and additional metadata. Let's see what happens for our integer addition, when the times come to generate the code for its VCode equivalent &lt;code&gt;AluRRR&lt;/code&gt; on &lt;code&gt;aarch64&lt;/code&gt; (in &lt;code&gt;cranelift/codegen/src/isa/aarch64/inst/emit.rs&lt;/code&gt;):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// We match on the VCode&amp;#39;s identity here:&lt;/span&gt;
&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Inst&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AluRRR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alu_op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// First select the top 11 bits based on the ALU subopcode.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;top11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alu_op&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ALUOp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Add32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mb"&gt;0b00001011_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;ALUOp&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Add64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mb"&gt;0b10001011_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// etc&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Then decide the bits 10 to 15, based on the ALU subopcode as well.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bit15_10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;alu_op&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// other cases&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mb"&gt;0b000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// Then use an helper and pass forward the allocated physical registers&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// values.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sink&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;put4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;enc_arith_rrr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;top11&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bit15_10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And what's this &lt;code&gt;enc_arith_rrr&lt;/code&gt; doing, then?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;enc_arith_rrr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bits_31_21&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bits_15_10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Writable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Reg&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Reg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Reg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;u32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bits_31_21&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bits_15_10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;machreg_to_gpr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_reg&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;machreg_to_gpr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;machreg_to_gpr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Encoding the instruction parts (operands, register mentions) is a lot of bit twiddling and fun. We do so for each VCode instruction, until we've generated the whole function's body. If you remember correctly, at this point register allocation may have added some spills/reloads/move instructions. From the codegen's point of view, these are just regular instructions with precomputed operands (either real registers, or memory operands involving the stack pointer), so they're not treated particularly and they're just generated the same way other VCode instructions are.&lt;/p&gt;
&lt;p&gt;More work is done by the codegen backend then, to optimize blocks placement, compute final branch offsets, etc. If you're interested by this, I strongly encourage you to go read &lt;a href="https://cfallin.org/blog/2021/01/22/cranelift-isel-2/"&gt;this blog post&lt;/a&gt; by Chris Fallin. After this, we're finally done: we've produced a code buffer, as well as external relocations (to other functions, memory addresses, etc.) for a single function. The code generator's task is complete: the final steps consist in linking and, optionally, producing an executable binary.&lt;/p&gt;
&lt;h2 id="mission-accomplished"&gt;&lt;a class="toclink" href="#mission-accomplished"&gt;Mission accomplished!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So, we're done for today! Thanks for reading this far, hope it has been a useful and pleasant read to you! Feel free to reach out to me on the &lt;a href="https://twitter.com/bnjbvr"&gt;twitterz&lt;/a&gt; if you have additional remarks/questions, and to go contribute on &lt;a href="https://github.com/bytecodealliance/wasmtime"&gt;Wasmtime/Cranelift&lt;/a&gt; if this sort of things is interesting to you 😇. Until next time, take care of yourselves!&lt;/p&gt;
&lt;p&gt;Thanks to &lt;a href="https://cfallin.org"&gt;Chris Fallin&lt;/a&gt; for reading and suggesting improvements to this blog post.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Really, Rust &lt;em&gt;is&lt;/em&gt; the DSL. It was Python code before, that had the advantage to be faster to update. Yet it was doing a lot of magic behind the curtain, which wasn't very friendly for new people trying to learn and use Cranelift. Despite a statically typed language helping for exploration through tooling, this meta-language is to partially disappear in the long run, see Chris' &lt;a href="https://cfallin.org/blog/2020/09/18/cranelift-isel-1/"&gt;blog post&lt;/a&gt; on this topic.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;Aarch64 connoisseurs may notice that there are other ways to encode an addition. Say, if one of the input operands was the result of a bit shift instruction by an immediate value, then it's possible to &lt;em&gt;embed&lt;/em&gt; the shift within the add, so we end up with fewer machine instructions (and lower the register pressure). This other possible encoding is sufficiently different in terms of register allocation and code generation that it justifies having its own VCode instruction. &lt;code&gt;AluRRR&lt;/code&gt; is simpler in the sense that it's only concerned with register inputs and outputs, thus a perfect example for this post.&amp;#160;&lt;a class="footnote-backref" href="#fnref:4" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;What's an integer overflow for signed integer division? Consider an integer value represented on &lt;code&gt;N&lt;/code&gt; bits. If you try to divide the smallest integer value &lt;code&gt;-2**N&lt;/code&gt; by &lt;code&gt;-1&lt;/code&gt;, it should return &lt;code&gt;2**N&lt;/code&gt;, but this is out of range, since the biggest signed integer value we can represent on &lt;code&gt;N&lt;/code&gt; bits is &lt;code&gt;(2**N) - 1&lt;/code&gt;! So this will overflow and be set to &lt;code&gt;-2**N&lt;/code&gt;, which is the initial value, but not the correct result. Good luck debugging this without a software trap!&amp;#160;&lt;a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;Register moves may be introduced because a successor block (in the control flow graph) expects a given virtual register to live in a particular real register, or because a particular instruction requires a virtual register to be allocated to a &lt;em&gt;fixed&lt;/em&gt; real register that's busy: regalloc can then temporarily divert the busy register into another unused register.&amp;#160;&lt;a class="footnote-backref" href="#fnref:5" title="Jump back to footnote 4 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:8"&gt;
&lt;p&gt;The &lt;code&gt;c&lt;/code&gt; in &lt;code&gt;rcx&lt;/code&gt; actually stands for &lt;code&gt;count&lt;/code&gt;; this is a property inherited from former CPU designs.&amp;#160;&lt;a class="footnote-backref" href="#fnref:8" title="Jump back to footnote 5 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:7"&gt;
&lt;p&gt;Unless this move carries sign- or zero-extending semantics, which is the case for e.g. x86's 32-bits &lt;code&gt;mov&lt;/code&gt; instructions on a 64-bits architecture.&amp;#160;&lt;a class="footnote-backref" href="#fnref:7" title="Jump back to footnote 6 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;Relocations are placeholders for information we don't have &lt;em&gt;yet&lt;/em&gt; access to. For instance, when we're generating jump instructions, the jump targets offsets are not determined yet. So we record where the jump instruction is in the code stream, as well as which control flow block it should jump into, so we can &lt;em&gt;patch it&lt;/em&gt; later when the final offsets are known: that's the content of our relocation.&amp;#160;&lt;a class="footnote-backref" href="#fnref:6" title="Jump back to footnote 7 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Wed, 17 Feb 2021 19:00:00 +0100</pubDate><guid isPermaLink="false">tag:bouvier.cc,2021-02-17:/cranelift-codegen-primer/</guid><category>blog</category><category>compilers</category><category>opensource</category><category>mozilla</category></item><item><title>Botzilla, a multi-purpose Matrix bot tuned for Mozilla</title><link>https://bouvier.cc/botzilla/</link><description>&lt;p&gt;Over the last year, Mozilla has decided to shut down the IRC network and
replace it with a more modern platform. To my greatest delight, &lt;a href="http://exple.tive.org/blarg/2019/12/19/over-the-line/"&gt;the Matrix
ecosystem has been
selected&lt;/a&gt; among all the
possible replacements. For those who might not know Matrix, it's a modern,
decentralized protocol, using plain HTTP JSON-formatted endpoints,
well-documented, and it implements both features that are common in recent
messaging systems (e.g. file attachments, message edits and deletions), as well
as those needed to handle large groups (e.g. moderation tools, private rooms,
invite-only rooms).&lt;/p&gt;
&lt;p&gt;In this post I reflect on my personal history of writing chat bots, and then
present a panel of features that the bot has, some user-facing ones, some
others that embody what I esteem to be a sane, well-behaved Matrix bot.&lt;/p&gt;
&lt;h2 id="but-first-some-history"&gt;&lt;a class="toclink" href="#but-first-some-history"&gt;but first, some history&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Back in 2014 when I was an intern at Mozilla, I made a silly IRC JavaScript bot
that would quote the @horsejs twitter account, when asked to do so. Then a few
other useless features were added: "karma" tracking &lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;, being a karma
guardian angel (lowering the karma of people lowering the karma of some
predefined people), keeping track of contextless quotes from misc people...&lt;/p&gt;
&lt;p&gt;Over time, it slowly transformed into an IRC bot &lt;em&gt;framework&lt;/em&gt;, with &lt;em&gt;modules&lt;/em&gt;
you could attach and configure at startup, setting which rooms the bot would
join, what should be the cooldowns for message sending (more on this later),
and so much more! Hence it was renamed &lt;em&gt;meta-bot&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="an-aside-on-the-morality-of-bots"&gt;&lt;a class="toclink" href="#an-aside-on-the-morality-of-bots"&gt;an aside on the morality of bots&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I find making bots a fun activity, since once you've passed the step of
connecting and sending messages, the rest is mostly easy (&lt;em&gt;cough cough regular
expressions cough cough&lt;/em&gt;) and creative work. And it's unfortunately easy to be
reckless too.&lt;/p&gt;
&lt;p&gt;At this time, I never considered the potentially bad effects of quoting text
from a random source, viz. fetching tweets from the @horsejs account. If the
source would return a message that was inconsiderate, rude, or even worse,
aggressive, then the bot would replicate this behavior. It is a real issue
because although the bot doesn't think by itself and doesn't &lt;em&gt;mean&lt;/em&gt; any harm,
its programmers can do better, and they should try to avoid these issues at all
costs. A chat bot replicates the culture of the engineers who made it on one
hand, but also contributes to propagating this culture in the chat rooms it
participates in, &lt;em&gt;normalizing&lt;/em&gt; it to the chat participants.&lt;/p&gt;
&lt;p&gt;My bot happened to be well-behaved most of the time... until one time where it
was not. After noticing the incident and expressing my deepest apologies, I
deactivated the module and went through the whole list of modules, to make sure
none could cause any harm, in any possible way. I should have known better in
the first place! I am really not trying to signal my own virtue, since I failed
in a way that should have been predictable. I hope by writing this that other
people may reflect about the actions of their bots as well, in case they could
be misbehaving like this.&lt;/p&gt;
&lt;h3 id="the-former-fleet-of-mozilla-bots"&gt;&lt;a class="toclink" href="#the-former-fleet-of-mozilla-bots"&gt;the former fleet of mozilla bots&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There were a few other useful IRC bots (of which I wasn't the author) hanging
out in the Mozilla IRC rooms, notably
&lt;a href="https://github.com/globau/firebot"&gt;Firebot&lt;/a&gt; and
&lt;a href="https://wiki.mozilla.org/Mrgiggles"&gt;mrggigles&lt;/a&gt;. The latter probably started as
a joke too, to enumerate puns from a list in the JavaScript channel. Then it
outgrew its responsibilities by helping with a handful of requests: who can
review this or this file in Mozilla's source code? what's the status of the
continuous integration trees? can this particular C++ function used in Gecko
cause a garbage collection?&lt;/p&gt;
&lt;p&gt;When we moved over to Matrix, the bots unfortunately became outdated, since the
communication protocol (IRC) they were using was different. We could have
ported them to the Matrix protocol, but the Not-Invented-Here syndrom was
strong with this one: I've been making bots for a while, and I was personally
interested in the Matrix protocol and trying out the JS facilities offered by
the Matrix ecosystem.&lt;/p&gt;
&lt;h2 id="botzilla-features"&gt;&lt;a class="toclink" href="#botzilla-features"&gt;&lt;strong&gt;Botzilla features&lt;/strong&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So I've decided to write &lt;a href="https://github.com/bnjbvr/botzilla"&gt;Botzilla&lt;/a&gt;, a
successor in spirit to &lt;em&gt;meta-bot&lt;/em&gt; and &lt;em&gt;mrgiggles&lt;/em&gt;, written in TypeScript. This
is a very &lt;em&gt;unofficial&lt;/em&gt; bot, tailored for Mozilla's needs but probably useful in
other contexts. I've worked on it informally as a side-project, on my &lt;em&gt;copious&lt;/em&gt;
spare time. Crafting tools that show useful to other people has been sufficient
a reward to motivate me to work on it, so it's been quite fun!&lt;/p&gt;
&lt;p&gt;&lt;img alt="Botzilla's logo" src="https://bouvier.cc/img/2020-11-12_botzilla/logo.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Botzilla's logo, courtesy of &lt;a href="https://nical.github.io/index.html"&gt;Nical&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Let's take a look at all the features that the bot offers, at this point.&lt;/p&gt;
&lt;h3 id="uuid-generate-unique-ids"&gt;&lt;a class="toclink" href="#uuid-generate-unique-ids"&gt;&lt;strong&gt;uuid: Generate unique IDs&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This was a feature of Firebot, and easy enough to replicate, so this was the
test feature for the Matrix bot. When saying &lt;code&gt;!uuid&lt;/code&gt;, the bot will
automatically generate a unique id (using uuid v4), guaranteed GMO-free and
usable in any context that would require it. This was the first module,
designed to test the framework.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Demo of uuid" src="https://bouvier.cc/img/2020-11-12_botzilla/uuid.png"&gt;&lt;/p&gt;
&lt;h3 id="treestatus-inform-about-ci-tree-status"&gt;&lt;a class="toclink" href="#treestatus-inform-about-ci-tree-status"&gt;&lt;strong&gt;treestatus: Inform about CI tree status&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Mozilla developers tend to interact a lot with the continuous integration
trees, because code is sometimes landed, sometimes backed out (sorry/thank you
sheriffs!), sometimes merged across branches. This leads to the integration
trees being closed. Before we had the feature to automatically land patch
stacks when the trees reopened, it was useful to be able to get the open/close
status of a tree. Asking &lt;code&gt;!treestatus&lt;/code&gt; will answer with a list of the status of
some &lt;em&gt;common&lt;/em&gt; trees. It is also possible to request the status of a particular
tree, e.g. for the "mozilla-central" tree, by asking &lt;code&gt;!treestatus
mozilla-central&lt;/code&gt; (or just &lt;code&gt;central&lt;/code&gt;, as a handy shortcut).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Demo of treestatus" src="https://bouvier.cc/img/2020-11-12_botzilla/treestatus.png"&gt;&lt;/p&gt;
&lt;h3 id="expand-bug-status"&gt;&lt;a class="toclink" href="#expand-bug-status"&gt;&lt;strong&gt;Expand bug status&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you have ever interacted with Mozilla's code, there's chances that you've
used Bugzilla, and mentioned bug numbers in conversations. The bot caches any
message containing &lt;code&gt;bug XXX&lt;/code&gt; and will respond with a link to this bug, the
nickname of the person assigned to this bug if there's one, and the summary of
this bug, if it's public. This is by far the most used and useful module, since
it doesn't require a special incantation, but will react automatically to a lot
of messages written with no particular intent (see below where it's explained
how to not be spammy, though).&lt;/p&gt;
&lt;p&gt;&lt;img alt="Demo of expand-bug" src="https://bouvier.cc/img/2020-11-12_botzilla/expand-bug.png"&gt;&lt;/p&gt;
&lt;h3 id="who-can-review-x"&gt;&lt;a class="toclink" href="#who-can-review-x"&gt;Who Can Review X?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This was a very nice feature that mrgiggles had: ask for potential reviewers
for a particular file in the Gecko source tree and get a list of most recent
reviewers. Botzilla replicates this, when seeing the trigger: &lt;code&gt;who can review
js/src/wasm/WasmJS.cpp?&lt;/code&gt;. The list of potential reviewers is extracted from
Mercurial logs, looking for the N last reviewers of this particular file.&lt;/p&gt;
&lt;p&gt;As a bonus, there's no need to pass the full path to the file, if the file's
name is unique in the tree's source code. Botzilla will trigger a search in
Searchfox, and will use the unique name in the result list, if there's such a
unique result. The previous example thus can be shortened to &lt;code&gt;who can review
WasmJS.cpp?&lt;/code&gt; since the file's name is unique in the whole code base.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Demo of who can review" src="https://bouvier.cc/img/2020-11-12_botzilla/who-can-review.png"&gt;&lt;/p&gt;
&lt;h3 id="githubgitlab-issuespmrs"&gt;&lt;a class="toclink" href="#githubgitlab-issuespmrs"&gt;{Github,Gitlab} {issues,{P,M}Rs}&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is possible for a room administrator to "connect" a given Matrix room to a
Github repository. Later on, any mention of issues or pull requests by their
number, e.g. &lt;code&gt;#1234&lt;/code&gt;, will make Botzilla react with the summary and a link to
the issue/PR at stake.&lt;/p&gt;
&lt;p&gt;This also works for Gitlab repositories, with slight differences: the
administrator has to precise what's the root URL of the Gitlab instance (since
Gitlab can be selfhosted). Issues are caught when numbers follows a &lt;code&gt;#&lt;/code&gt; sign,
while merge requests are caught when the numbers follow a &lt;code&gt;!&lt;/code&gt; sign.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Demo of gitlab" src="https://bouvier.cc/img/2020-11-12_botzilla/gitlab.png"&gt;&lt;/p&gt;
&lt;h3 id="tweettoot-post-on-twittermastodon"&gt;&lt;a class="toclink" href="#tweettoot-post-on-twittermastodon"&gt;!tweet/!toot: Post on Twitter/Mastodon&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An administrator can configure a room to tie it up to a Twitter (respectively
Mastodon) user account, using API tokens. Then, any person with an
administrative role can post messages with &lt;code&gt;!tweet something shocking for the
bird site&lt;/code&gt;(respectively &lt;code&gt;!toot something heartful for the mammoth site&lt;/code&gt;). This
makes it possible to allow other people to post on these social networks
without the need to give them the account's password.&lt;/p&gt;
&lt;p&gt;Unfortunately, the Twitter module hasn't ever been tested, since when I've
tried to create a developer account, Twitter accepted it after a few days but
then never displayed the API tokens on the interface. The support also never
answered when I asked for help. Thankfully Mastodon can be self-hosted and thus
it is easier to test. I'm happy to report that it works quite well!&lt;/p&gt;
&lt;h3 id="confession-and-histoire"&gt;&lt;a class="toclink" href="#confession-and-histoire"&gt;&lt;code&gt;confession&lt;/code&gt; and histoire&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is quite common in teams to set up regular standup meetings, where everyone
in the team announces what they've been working on in the last few days or
week. It also strikes me as important for personal recognition, including
towards management, to be able to &lt;em&gt;show off&lt;/em&gt; (just a bit!) what you've
accomplished recently, and to remember this when times are harder (see also
&lt;a href="https://jvns.ca/blog/brag-documents/"&gt;Julia Evans' blog post on the topic&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;There's a Botzilla module for this. Every time someone starts a message with
&lt;code&gt;confession:&lt;/code&gt;, then everything after the colon will be saved in a database
(...wait for it!). Then, all the confessions are displayed on the
&lt;a href="https://robotzilla.github.io/histoire"&gt;Histoire&lt;/a&gt; &lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt; website, with one
message feed per user. Note it is possible to send confessions privately to
Botzilla (that doesn't affect the frontend though, which is open and public to
all!), or in a public channel. Public channels somehow equate to team members,
so channels also get their own pages on the frontend.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Demo of confession" src="https://bouvier.cc/img/2020-11-12_botzilla/confession.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Screenshot of Histoire" src="https://bouvier.cc/img/2020-11-12_botzilla/histoire.png"&gt;&lt;/p&gt;
&lt;p&gt;Now the fun/cursed part is how all of this &lt;em&gt;works&lt;/em&gt;. This was implemented in
&lt;em&gt;mrgiggles&lt;/em&gt;, and I liked it a lot, since it required no kind of backend or
frontend server. How so? By (ab)using Github files as the database and Github
pages as the frontend. Sending a confession will trigger a request to a Github
endpoint to find a database file segregated by time, then it will trigger
another request to create/modify it with the content of the confession. The
frontend then uses other requests to public Github APIs to read the confessions
before dynamically rendering those. Astute readers will notice that under a lot
of confession activity, the bot would be a bit slowed down by Github's API use
rates. In this case, there's some exponential backoff behavior before trying to
re-send unsaved confessions to Github. Overall it works great, and API
limitation rates have never quite been a problem.&lt;/p&gt;
&lt;h2 id="intrinsic-features-theyre-good-bots-bront"&gt;&lt;a class="toclink" href="#intrinsic-features-theyre-good-bots-bront"&gt;&lt;strong&gt;Intrinsic features: they're good bots, bront&lt;/strong&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In addition to all the user-facing features, the bot has a few other
interesting attributes that are more relevant to consider from a framework
point of view. Hopefully some of these ideas can be useful for other bot
authors!&lt;/p&gt;
&lt;h3 id="join-all-the-rooms"&gt;&lt;a class="toclink" href="#join-all-the-rooms"&gt;&lt;strong&gt;Join All The Rooms!&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Every time the bot is invited to a channel, be it public or private, it will
join the channel, making it easy to use in general. It was implemented for free
by &lt;a href="https://github.com/turt2live/matrix-js-bot-sdk"&gt;the JS framework I've been
using&lt;/a&gt;, and it is a
definitive improvement over the IRC version of the bot.&lt;/p&gt;
&lt;p&gt;Sometimes Matrix rooms are upgraded to a new version of the room. The bot will
try to join the upgraded room if it can, keeping all its room settings intact
during the transition.&lt;/p&gt;
&lt;h3 id="thou-shalt-not-spam"&gt;&lt;a class="toclink" href="#thou-shalt-not-spam"&gt;&lt;strong&gt;Thou shalt not spam&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To avoid spamming the channel, especially for modules that are &lt;em&gt;reactions&lt;/em&gt; to
other messages (think: bug numbers, issues/pull requests mentions), the bot has
had to learn how to keep quiet. There are two rules triggering the quieting
behavior:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if the bot has already reacted less than N minutes ago (where N is a
  configurable amount) in the same room,&lt;/li&gt;
&lt;li&gt;or if it has already reacted to some entity in a message, and there's been
  fewer than M messages in between the last reaction and the last message
  mentioning the same entity in the same room (M is also configurable)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If any of these two criteria is met, then the bot will keep quiet and it will
not react to another similar message. The combination of these two has proven
over time to be quite solid in my experience, based on observing the bot's
behavior and public reactions to its behavior.&lt;/p&gt;
&lt;p&gt;Some similar mechanism is used for the &lt;em&gt;confession&lt;/em&gt; module: on a &lt;em&gt;first&lt;/em&gt;
confession, the bot will answer with a message saying it has seen the
confession, including a link to where it is going to be posted, and will add an
emoji "eyes" reaction to the message. Posting this long form message could be
quite spammy, if there's a lot of confessions around the same time. Under the
same criteria, it will just react with an "eyes" emoji to other confessions.
Later on, it'll resend the full message, once both criterias aren't blocking it
from doing so.&lt;/p&gt;
&lt;h3 id="decentralized-administration-self-service"&gt;&lt;a class="toclink" href="#decentralized-administration-self-service"&gt;&lt;strong&gt;Decentralized administration self-service&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The bot can be administrated, by discussing with it using the &lt;code&gt;!admin&lt;/code&gt; command.
This can happen in both a private conversation with it, or in public channels,
yet it is recommended to do so in private channels. To confirm that an admin
action has succeeded, it'll use the thumbs-up emoji on the message doing the
particular action.&lt;/p&gt;
&lt;p&gt;To have a single administrator for the bot would be quite the burden, and it is
not resilient to people switching roles, leaving the company, etc. Normally
you'd solve this by implementing your own access control lists. Fortunately,
Matrix already has a concept of &lt;em&gt;power levels&lt;/em&gt; that assigns roles to users,
among which there are the administrator and moderator roles.&lt;/p&gt;
&lt;p&gt;The bot will rely on this to decide to which requests it will answer. Somebody
marked as an administrator or a moderator of a room can administrate Botzilla
in this particular room, using &lt;a href="https://github.com/bnjbvr/botzilla#admin"&gt;the &lt;code&gt;!admin&lt;/code&gt;
commands&lt;/a&gt;. There's still a
super-admin role, that must be defined in the configuration, in case things go
awry. While administrators only have power over the current room, a super-admin
can use its super-powers to change anything in any room. This decentralization
of the administrative roles makes it easy to have different settings for
different rooms, and to rely a bit less on single individuals.&lt;/p&gt;
&lt;h3 id="key-value-store"&gt;&lt;a class="toclink" href="#key-value-store"&gt;&lt;strong&gt;Key-value store&lt;/strong&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In general, the bot contains a key-value store implemented in an sqlite
database, making it easy to migrate and add context that's preserved across
restarts of the bot. This is used to store private information like user
repository information and settings for most rooms. Conceptually, each pair of
room and module has its own key-value store, so that there's no risk of
confusion between different rooms and modules. There's also a key-value
per-module store that's applicable to all the rooms, to represent global
settings. If there's some non-global (per room) settings for a room, these are
preferred over the global settings.&lt;/p&gt;
&lt;h3 id="self-documentation"&gt;&lt;a class="toclink" href="#self-documentation"&gt;Self-documentation&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each chat module is implemented as a ECMAScript module and must export an help
string along the main reaction function. This is then captured and aggregated
as part of an &lt;code&gt;!help&lt;/code&gt; command, that can be used to request help about usage of
the bot. The main help message will display the list of all the enabled
modules, and help about a specific module may be queried with e.g. &lt;code&gt;!help
uuid&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="future-work-and-conclusion"&gt;&lt;a class="toclink" href="#future-work-and-conclusion"&gt;Future work and conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If I were to start again, I'd do a few things differently:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;now that the Rust ecosystem around the Matrix platform has matured a bit, I'd
  probably write this bot in Rust. Starting from JavaScript and moving to
  TypeScript has helped me catch a few static issues. I'd expect moving to Rust
  would help handling Matrix events faster, provide end-to-end encryption
  support for free, and be quite pleasant to use in general thanks to the
  awesome Rust tooling.&lt;/li&gt;
&lt;li&gt;use a real single-page app framework for the Histoire website. Maybe? I mean
  I'm a big fan of VanillaJS, but using it means re-creating your own Web
  framework like thing to make it nice and productive to use.&lt;/li&gt;
&lt;li&gt;despite being a fun hack, using Github as a backend has algorithmic
  limitations, that can make the web app sluggish. In particular, a combined
  feed for N users on M &lt;em&gt;eras&lt;/em&gt; (think: periods) will trigger NxM Github API
  requests. Using a plain database with a plain API would probably be simpler
  at this point. This is mitigated with an in-memory cache so only the first
  time all the requests happen, but crafting my own requests would be more
  expressive and efficient, and allow for more features too (like displaying
  the list of rooms on the start view).&lt;/li&gt;
&lt;li&gt;provide a (better) commands parser. Regular expressions in this context are a
  bit feeble and limited. Also right now each module could in theory reuse the
  same command triggers as another one, etc.&lt;/li&gt;
&lt;li&gt;implement the chat modules in WebAssembly :-) In fact, I think there's a
  whole business model which would consist in having the bot framework
  including a wasm VM, and interacting with different communication platforms
  (not restricted to Matrix). Developers in such a bot platform could choose
  which source language to use for developing their own modules. It ought to be
  possible to define a clear, restricted, WASI-like capabilities-based
  interface that gets passed to each chat module. In such a sandboxed
  environment, the responsibility for hosting the bot's code is decoupled from
  the responsibility of writing modules. So a company could make the platform
  available, and paying users would develop the modules and host them. Imagine
  &lt;code&gt;git push&lt;/code&gt;ing your chat modules and they get compiled to wasm and deployed on
  the fly. But I digress! (Please do not forget to credit me with a large $$$
  envelope/a nice piece of swag if implementing this &lt;em&gt;at least&lt;/em&gt; multi-billion
  dollars idea.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I'd like to finish by thanking the authors of the previous Mozilla bots, namely
&lt;strong&gt;sfink&lt;/strong&gt; and &lt;strong&gt;glob&lt;/strong&gt;: your puppets have been incredible sources of
inspiration. Also huge thanks to the people hanging in the &lt;code&gt;matrix-bot-sdk&lt;/code&gt;
&lt;a href="#matrix-bot-sdk:t2bot.io"&gt;chat room&lt;/a&gt;, who've answered questions and provided
help in a few occasions.&lt;/p&gt;
&lt;p&gt;I hope you liked this presentation of Botzilla and its features! Of course, all
the code is free and open-source, including &lt;a href="https://github.com/bnjbvr/botzilla"&gt;the
bot&lt;/a&gt; as well as &lt;a href="https://github.com/robotzilla/histoire"&gt;the histoire
frontend&lt;/a&gt;. At this point it is
addressing most of the needs I had, so I don't have immediate plans to extend
it further. I'd happily take contributions, though, so feel free to chime in if
you'd like to implement anything! It's also a breeze to run on any machine,
thanks to Docker-based deployment. Have fun with it!&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Karma is an IRC idiosyncrasy, in which users rate up and down other users
  using their nickname suffixed with ++ or --. Karma tracking consists in
  keeping scores and displaying those.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Histoire is the French for "history" and "story". Inherited from Steve
  Fink's very own mrgiggles :-)&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Thu, 12 Nov 2020 18:49:00 +0100</pubDate><guid isPermaLink="false">tag:bouvier.cc,2020-11-12:/botzilla/</guid><category>blog</category><category>mozilla</category><category>opensource</category></item><item><title>Improving my Github workflow</title><link>https://bouvier.cc/github-workflow/</link><description>&lt;p&gt;Since I've been working on a &lt;a href="https://github.com/CraneStation/Cranelift"&gt;Github
project&lt;/a&gt; for a while now, I
thought now would be a good time to gather ways to make it easier to work with
Github pull requests (PRs). In particular, it's easy to drown yourself in the
incoming flow of Github emails.&lt;/p&gt;
&lt;p&gt;This post is for you if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you get lost in tracking which pull requests need attention from you, be it
  either review requests or just mentions.&lt;/li&gt;
&lt;li&gt;you would like to strike a better work-life balance when it gets to Github
  notifications.&lt;/li&gt;
&lt;li&gt;you would like to filter Github email notifications in smarter ways.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here are a few tricks I've collected over the years that make it easier to deal
with a few things, focusing on Github notifications and emails, since they were
the largest issue for me. This is not an exhaustive list of all the nice
features Github has, or all the WebExtensions that could help with Github: it
is a few things that work for me and are worth sharing. Note that I go from the
most mundane to the more specific advices here.&lt;/p&gt;
&lt;h3 id="notifications-dashboard"&gt;&lt;a class="toclink" href="#notifications-dashboard"&gt;Notifications dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you're working on several projects, Github can end up sending you too many
email notifications.&lt;/p&gt;
&lt;p&gt;It's possible to disable some kinds of notifications entirely &lt;a href="https://github.com/settings/notifications"&gt;in the
settings&lt;/a&gt;, but that's too radical
for my needs.&lt;/p&gt;
&lt;p&gt;However, Github has a &lt;a href="https://github.com/notifications"&gt;notification
dashboard&lt;/a&gt; that displays all the activity
related to repositories you're watching or issues/pull-requests you're involved
in. It's easy to dismiss all the notifications of all projects at once, or per
project. There's a tab on the left that allows to select more precisely your
level of involvement in the issue: did you participate in it? You can also save
some notifications for later, so they're not deleted once you've clicked them;
they'll appear under the "Saved for later" tab — I just discovered this!&lt;/p&gt;
&lt;p&gt;Note that Github may also send these notifications by email, if you've decided
to do so. In this case, I'd strongly recommend allowing the downloads of images
in Github emails. Despite the bad effect on your privacy this might have by
allowing user tracking, it will also synchronize the notifications' read state,
which is nice.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Notification dashboard
count" src="https://bouvier.cc/img/2019-10-07_github/github-notification-dashboard.png"&gt;&lt;/p&gt;
&lt;p&gt;See how I am totally in control of my notifications? Truth is, I don't need
notifications in general, because I'm usually more interested in reviews I need
to receive and give.&lt;/p&gt;
&lt;h3 id="pull-requests-dashboard"&gt;&lt;a class="toclink" href="#pull-requests-dashboard"&gt;Pull requests dashboard&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Github allows to assign a reviewer to a pull request. At Mozilla, we
require a formal review for each change in the code base, unless it's really
not meaningful (like, removing trailing whitespaces). Even documentation and
tests changes may require a review, depending on the rules of the code module
you're working on.&lt;/p&gt;
&lt;p&gt;It is very common that a pull request is received with requests for additional
changes. In this case, it is important to explicitly &lt;strong&gt;re-request a review&lt;/strong&gt;,
otherwise this breaks all the review tracking Github proposes.&lt;/p&gt;
&lt;p&gt;Now Github has two interesting pages for this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a list of all the &lt;a href="https://github.com/pulls"&gt;pull requests you have created&lt;/a&gt;
  and that aren't closed, so you can assign reviewers and follow PR's progress
  over time;&lt;/li&gt;
&lt;li&gt;a list of all the &lt;a href="https://github.com/pulls/review-requested"&gt;pull requests you have been assigned to as a
  reviewer&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="navigating-files-quicker-addon"&gt;&lt;a class="toclink" href="#navigating-files-quicker-addon"&gt;Navigating files quicker (addon)&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When I know my way around a project, I'll frequently need to see the content of
a particular file or directory, that might be a few directories deep. On
Github, this means going to the files view, clicking once per directory (at
most), and finding the file I want.&lt;/p&gt;
&lt;p&gt;The pull request view doesn't show the directory hierarchy and which files of
which directory have been touched, which is a light inconvenience too.&lt;/p&gt;
&lt;p&gt;Good news, everyone! There is one WebExtension called
&lt;a href="https://www.octotree.io/"&gt;Octotree&lt;/a&gt; that adds a directory view within a panel
to the left of Github's UI. By default, it's folded and doesn't take much
space; you need to hover it with the mouse to make it appear. On pull requests,
it will show files that have been modified with the diff summary for each file.
Note the website shows features from the PRO version, but there's a free
version that addresses the needs detailed above.&lt;/p&gt;
&lt;p&gt;This is an example of the Octotree panel on our project's repository:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Octotree example" src="https://bouvier.cc/img/2019-10-07_github/github-octotree.png"&gt;&lt;/p&gt;
&lt;p&gt;To be honest, I haven't investigated using the search bar, which could be quite
handy for this too, especially thanks to keyboard shortcuts.&lt;/p&gt;
&lt;h3 id="dealing-with-work-and-personal-projects"&gt;&lt;a class="toclink" href="#dealing-with-work-and-personal-projects"&gt;Dealing with work and personal projects&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you're using Github for personal and work related projects, you might have
been bothered by work emails coming into your personal mailbox. That has
happened to me in the past, causing some unnecessary mental load over the
weekend and unnecessarily breaking the state of relaxation.&lt;/p&gt;
&lt;p&gt;Fortunately, Github allows you to &lt;a href="https://github.com/settings/notifications#organization_routing"&gt;redirect emails from a particular Github
Organization to a specific email
address&lt;/a&gt;. Of
course, this only works when the repository is owned by an organization and
you're part of this organization.&lt;/p&gt;
&lt;p&gt;I'm lucky to work on such projects at the moment. It's not a silver bullet
though, because some projects are sometimes owned by personal accounts, making
this trick useless. As far as I know, there are no good solutions in this case.&lt;/p&gt;
&lt;h3 id="email-filters"&gt;&lt;a class="toclink" href="#email-filters"&gt;Email filters&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The biggest remaining offender certainly is Github emails, in general.
Fortunately, Github has made it easy to filter them. I'll mention examples in
the Gmail email client, since that's what we're using at work, but these apply
to any other modern email client too.&lt;/p&gt;
&lt;h4 id="filter-by-project"&gt;&lt;a class="toclink" href="#filter-by-project"&gt;Filter by project&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Each email coming from a specific project comes with a mailing &lt;code&gt;list-id&lt;/code&gt;, which
is a specific header that some email clients know how to interpret. For
instance, in Gmail, when you click on the small arrow next to the list of
recipients, you'll see many details about the current email, including, if
there's one, the "mailing-list" id, and a link to automatically create a filter
for this mailing-list. That allows you to create a particular directory/tag in
which the filter can automatically put all the emails with this id.&lt;/p&gt;
&lt;h4 id="filter-by-reason"&gt;&lt;a class="toclink" href="#filter-by-reason"&gt;Filter by reason&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;In addition to filtering by project (and this is where Gmail tags /
Thunderbird's &lt;a href="https://support.mozilla.org/en-US/kb/using-saved-searches"&gt;saved
searches&lt;/a&gt; truly
shine), it's also possible to infer more information from the Github email
notifications, by looking at the list of recipients or custom email headers.&lt;/p&gt;
&lt;p&gt;Indeed, when there's a specific reason why an email was sent to you, Github
will add a (fake) recipient in the CC field, its address username being the
reason why the email was sent to you. For instance, in an email telling me that
somebody requested a review from me, the email address
&lt;code&gt;review_requested@github.com&lt;/code&gt; will appear in the CC list. If you look at the
full message, you'll also see the custom email header &lt;code&gt;X-GitHub-Reason&lt;/code&gt; set to
&lt;code&gt;review_requested&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;All the possible reasons are &lt;a href="https://help.github.com/en/articles/about-email-notifications#filtering-email-notifications"&gt;detailed in Github's
documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These extra CC email addresses and email headers allow creating very powerful
filters that add supplementary tags to an email. For me, they relate directly
to the &lt;em&gt;importance&lt;/em&gt; of the incoming email: reviews and mentions are usually
something I pay very close attention to, and thus they get filtered in a
special top-level tag in Gmail.&lt;/p&gt;
&lt;p&gt;Here's an example of all the information you might find about a given email in
Gmail: in particular, look at the CC list and mailing-list type ids.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Notification dashboard count" src="https://bouvier.cc/img/2019-10-07_github/github-email-example.png"&gt;&lt;/p&gt;
&lt;p&gt;Note that Gitlab also adds some &lt;a href="https://docs.gitlab.com/ee/workflow/notifications.html#email-headers"&gt;similar custom
headers&lt;/a&gt;
that can be filtered by some powerful email clients. I won't go into detail
about those.&lt;/p&gt;
&lt;h3 id="one-more-thing-mozillian-edition"&gt;&lt;a class="toclink" href="#one-more-thing-mozillian-edition"&gt;One more thing, Mozillian edition&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you're working on Mozilla code, Gecko and/or external projects, there's
this &lt;a href="https://github.com/mikeconley/myqonly/"&gt;neat addon&lt;/a&gt; that Mike Conley
made. It will add an icon to the Firefox button bar, showing you the number
of requests assigned to you on Github and Phabricator, as well as the number of
pending Bugzilla requests.&lt;/p&gt;
&lt;p&gt;It requires a minimal setup step for Github (filling your username) and
Bugzilla (adding a Bugzilla API token), and then it Just Works. It smartly
reuses a Phabricator token from the current Firefox Container's session, if
there's one.&lt;/p&gt;
&lt;p&gt;You may think that having such a display all the time might provoke anxiety
during non-working hours. And you'd be right to think so! So the author of the
addon has added a feature to &lt;strong&gt;not&lt;/strong&gt; display this information outside working
hours, that you can define as you like. Great stuff!&lt;/p&gt;
&lt;h3 id="thats-it-folks"&gt;&lt;a class="toclink" href="#thats-it-folks"&gt;That's it, folks!&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Thanks for reading this far! I hope this helped you to some extent, allowing
you to spend less time in Github and more time doing the actual work. If you
have more interesting tips for using Github effectively, feel free to add a
comment or ping me on &lt;a href="https://twitter.com/bnjbvr"&gt;twitter&lt;/a&gt;!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Thu, 10 Oct 2019 18:00:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2019-10-10:/github-workflow/</guid><category>blog</category><category>mozilla</category><category>opensource</category></item><item><title>A new blog theme!</title><link>https://bouvier.cc/a-new-blog-theme/</link><description>&lt;p&gt;Just a quick note! I've just updated my blog's design and UI so it is more
convenient, modern and light. It is still using the
&lt;a href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt; blog system, only the theme has
changed. The previous theme, &lt;a href="https://github.com/alexandrevicenzi/flex"&gt;Flex&lt;/a&gt;,
was elegant and it has been quite pleasant to use, but it had a few subtle
drawbacks that revealed as time went. Here I explain what were my needs, which
other blog designs inspired me, and link to all the different resources I've
used.&lt;/p&gt;
&lt;h2 id="embeds-tracking-and-comments"&gt;&lt;a class="toclink" href="#embeds-tracking-and-comments"&gt;Embeds: tracking and comments&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I use some embeds in my blog: since Pelican generates static files, it can't
handle more complicated features like counting visitors or a comment system.
Soon, I've wanted to get a rough idea of the number of visitors and where they
come from, to understand which posts are the most useful (and of course, to
bless my ego). I've been using self-hosted, open-source systems for that
purpose, like &lt;a href="https://matomo.org/"&gt;Matomo&lt;/a&gt; (née Piwik), because I don't want
my blog's visitors to get (even more) tracked by Google Analytics, which would
be counter to my values. This led to a meaningful contribution to add &lt;a href="https://github.com/alexandrevicenzi/Flex/pull/15"&gt;support
for Matomo&lt;/a&gt; in the theme, so
other people don't have to redo this work themselves!&lt;/p&gt;
&lt;p&gt;Later, I switched over to the &lt;a href="https://usefathom.com/"&gt;Fathom&lt;/a&gt; analytics
system, because it's lighter, it knows less about my visitors (only number of
visits/visitors by page and the referrer), and its dashboard is a gazillion
times faster to load (all it loads are static files!) than Matomo's. So I had
to tweak the theme for this too! And then, when I decided to add an embed for a
self-hosted, open-source comment system named &lt;a href="https://posativ.org/isso"&gt;isso&lt;/a&gt;
(think of it as an alternative to the centralized Disqus), I needed to add
support for it as well. This meant digging into the theme and understanding how
it works, and each time I wanted to add a new embed, I had to repeat this
process.&lt;/p&gt;
&lt;h2 id="css-and-markup"&gt;&lt;a class="toclink" href="#css-and-markup"&gt;CSS and markup&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After reading a well-written and quite interesting online class on typography
on &lt;a href="https://betterwebtype.com/"&gt;BetterWebType&lt;/a&gt; (read it if you haven't! it
helped me understanding why some websites were more pleasant to use, and put
explanations onto all the intuitions and feelings I had on the topic), I've
changed a few lines in the CSS source file, tweaking fonts, width, line height
etc.&lt;/p&gt;
&lt;p&gt;A few other changes affecting the markup also happened over time, for which I
had to add CSS rules. Of course there were a few conflicts with preexisting
rules, since that's pretty common in CSS; but the fact that I didn't write the
CSS rules in the first place made it harder to understand how and where these
rules were used.&lt;/p&gt;
&lt;h2 id="writing-my-own"&gt;&lt;a class="toclink" href="#writing-my-own"&gt;Writing my own&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I also got a bit bored of the design itself, especially the aside bar on the
left which felt a bit early 2010, as well as the overall sense of density. Some
other blogs' strong takes inspired me a lot: in particular, I'd like to point
to my colleague and friend &lt;a href="https://blog.paul.cx/"&gt;Paul Adenot's blog&lt;/a&gt;, and its
refined, minimalistic design (as well as its amazing body font, look at the
K/it or Q/uo ligatures, they're &lt;em&gt;insane&lt;/em&gt;). There's also the blog of &lt;a href="https://jvns.ca/"&gt;Julia
Evans&lt;/a&gt;, which in addition to containing amazingly instructive
blog posts about system programming, shows all the blog posts as a long list in
the index page, making it clear, informative and helping discoverability.&lt;/p&gt;
&lt;p&gt;With all of this in mind, since I had to acquire more control over the theme
anyway and I wanted it to look much different, I decided to write my own. Of
course, it's &lt;a href="https://github.com/bnjbvr/blog.benj.me/tree/sources/themes/modern"&gt;free
software&lt;/a&gt;.
This is what you should be seeing right now.&lt;/p&gt;
&lt;p&gt;As an extra to all the items I've mentioned before, I'd like to give a shoutout
to the open-source &lt;em&gt;fonts&lt;/em&gt; I've used. The header font is
&lt;a href="http://velvetyne.fr/fonts/bluu/"&gt;bluu&lt;/a&gt;, a font created by Jean-Baptiste
Morizot from the fantastic &lt;a href="http://velvetyne.fr"&gt;Velvetyne&lt;/a&gt; type foundry. Go
check it out if you're a typo nerd! or if you're looking for some original and
well-thought fonts. The body font is &lt;a href="https://rsms.me/inter/"&gt;Inter UI&lt;/a&gt;; it
feels quite modern and it has been designed with computer screens in mind.&lt;/p&gt;
&lt;p&gt;Previous vs new home page:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Previous home page" src="https://bouvier.cc/img/2019-06-13_new_blog/previous-index.png"&gt;
&lt;img alt="New home page" src="https://bouvier.cc/img/2019-06-13_new_blog/new-index.png"&gt;&lt;/p&gt;
&lt;p&gt;Previous vs new post page:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Previous post page" src="https://bouvier.cc/img/2019-06-13_new_blog/previous-post.png"&gt;
&lt;img alt="New post page" src="https://bouvier.cc/img/2019-06-13_new_blog/new-post.png"&gt;&lt;/p&gt;
&lt;h2 id="flex-thee-well"&gt;&lt;a class="toclink" href="#flex-thee-well"&gt;Flex thee well&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I still think Flex is a great theme to start with, and I'm thankful to the
authors for writing it in the first place, since it has served me well. Thanks!&lt;/p&gt;
&lt;p&gt;I'd also like to thank people who gave me feedback and helped me write the CSS
(me can't CSS) of this theme, including Flaburgan, Maiwann, Marien, Thomas
and other &lt;a href="https://framasoft.org/en"&gt;Framasoft&lt;/a&gt; friends.&lt;/p&gt;
&lt;p&gt;And thank &lt;strong&gt;you&lt;/strong&gt; for reading this far! I think blogging and self-hosting are
still important and relevant, to avoid depending on commercial platforms, like
Medium, which repeatedly tries to get you to subscribe, displays thousands of
popovers and attempts to abuse your attention into reading always more (and
spending more time on their website).  It's easy to host your own blog! Even if
you don't have your own server, you can use Github or
&lt;a href="https://docs.gitlab.com/ee/user/project/pages/"&gt;Gitlab&lt;/a&gt; pages, with fancy
automatic systems that make publishing a breeze.&lt;/p&gt;
&lt;p&gt;I'd be curious to hear your feedback on this new design, including code
improvements (remember? it's free software!). Feel free to type in a comment,
or hit me up on &lt;a href="https://twitter.com/bnjbvr"&gt;twitter&lt;/a&gt;!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Thu, 13 Jun 2019 19:00:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2019-06-13:/a-new-blog-theme/</guid><category>blog</category><category>opensource</category></item><item><title>Quatre ans de Kresus, bonjour Kresus.org</title><link>https://bouvier.cc/4-ans-de-kresus-bonjour-kresus-org/</link><description>&lt;h2 id="de-la-volonte-derriere-kresus"&gt;&lt;a class="toclink" href="#de-la-volonte-derriere-kresus"&gt;De la volonté derrière Kresus&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Il y a une dizaine d'années, alors fervent utilisateur de HomeBank, je découvre
avec stupéfaction et beaucoup d'intérêt l'application mobile de Linxo.  Ce
service permet de récupérer ses opérations bancaires depuis le site de sa
banque, de manière automatisée, tout en analysant les transactions et en
permettant de les catégoriser, afin de générer des graphes simples et clairs
pour expliquer aux utilisateur.ice.s comment évoluent leurs finances
personnelles : combien a été dépensé ou économisé tel mois ? quelles sont les
trois sources principales de dépenses au cours des six derniers mois ? J'ai
utilisé un peu cette application mobile à l'époque. Elle m'était très utile,
alors jeune étudiant, n'ayant qu'un budget limité et aucune idée de comment le
gérer.&lt;/p&gt;
&lt;h3 id="si-cest-gratuit-cest-quoi-le-produit"&gt;&lt;a class="toclink" href="#si-cest-gratuit-cest-quoi-le-produit"&gt;Si c'est gratuit, c'est quoi le produit ?&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Il m'est apparu assez vite que le service étant gratuit, Linxo devait avoir une
autre source de financement que l'unique option premium qu'ils proposaient
alors. En y réfléchissant un peu, on peut trouver plusieurs possibles intérêts
pour eux. Par exemple, ce pourrait être tout simplement de pouvoir récupérer
une grande quantité de données bancaires, utilisable comme source de données
pour un algorithme de catégorisation automatique. Un tel algorithme de
catégorisation pourrait ensuite être revendu à des services tiers. De mémoire,
j'ai aussi vu une autre source de financement basée sur des publicités ciblées.
Dans ce cas, le logiciel propose d'analyser les transactions bancaires pour
permettre d'identifier des coûts récurrents, et ensuite met en avant des offres
de services similaires d'entreprises partenaires ; le revenu est ici une
commission. Par exemple, si vous avez une assurance habitation dont l'échéance
est mensuelle, le système peut le détecter et vous proposer des publicités pour
d'autres assurances habitations moins chères (mais pas forcément équivalentes
!) chez des concurrents. Dans le pire des cas, l'intérêt caché pourrait être de
revendre des informations extraites des transactions bancaires, comme la
récurrence et les noms des enseignes où nous effectuons des paiements. Au
mieux, cela est effectué de manière anonyme et n'a pas une grande incidence
personnelle. Au pire, cela révèle des détails de notre intimité, notamment si
l'information est rattachée à une personne identifée. Ces informations peuvent
être très utiles pour les assurances et les banques pour évaluer divers
risques liés à des emprunts ou des polices d'assurance. Mais des entreprises
plus classiques peuvent également en faire usage, en mettant en place des
publicités ultra-ciblées qui touchent aux aspects émotionnels.&lt;/p&gt;
&lt;p&gt;De manière certaine, j'ai été immédiatement gêné par le fait de devoir confier
à une entreprise mes identifiants bancaires, à savoir mon login et mon mot de
passe, le sésame pour accéder au site de ma banque, attribuant parfois des
autorisations plus variées que la simple lecture seule, comme celle d'effectuer
des virements. Après cette réflexion, je me désinscris. Je cherche une
alternative libre aussi complète, car je veux être capable de vérifier dans le
code du logiciel ce qui est fait avec mes identifiants ; un
logiciel libre peut difficilement fomenter des coups fourrés. N'en trouvant
pas, je brandis ma liste de projets à long terme, aussi connue sous le nom de
liste des projets que je ne mettrai probablement jamais en place, ou encore
liste des rêves libristes. J'y ajoute une entrée : créer une alternative libre
et auto-hébergeable qui fasse la même chose que Linxo, sans trop savoir comment
m'y prendre.&lt;/p&gt;
&lt;h2 id="cozycloud-et-son-gestionnaire-de-finances-personnelles"&gt;&lt;a class="toclink" href="#cozycloud-et-son-gestionnaire-de-finances-personnelles"&gt;CozyCloud et son gestionnaire de finances personnelles&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Capture de cozypfm" src="https://bouvier.cc/img/2018-08-23-cozypfm.png"&gt;&lt;/p&gt;
&lt;p&gt;Un peu plus tard, je découvre CozyCloud, et notamment l'application
&lt;a href="https://github.com/seeker89/cozy-pfm"&gt;cozy-pfm&lt;/a&gt;, développée par un prestaire.
C'est ce clône libre dont j'ai tant rêvé. La clé qui me manquait, c'était
l'intégration avec l'outil pour récupérer les données bancaires : ce logiciel
s'appuie sur les épaules d'un outil complet de scrapping [1] libre,
&lt;a href="https://weboob.org"&gt;weboob&lt;/a&gt;. Très vite, l'application montre ses limites : des
doublons apparaissent dans mes opérations bancaires. En effet, l'outil de
scrapping est capable de nous fournir un cliché de nos comptes bancaires à un
instant donné. Un gestionnaire de finances personnelles essaie de mettre en
place une continuité, donc de joindre les instantanés en un film à 24 images
par seconde, qui retracerait l'historique plus complet de nos comptes. Mais
parfois, ce dernier se trompe parce qu'il ne dispose pas d'assez
d'informations, ou parce que les banques changent la manière dont sont
présentées les opérations au cours du temps (et ça arrive beaucoup plus souvent
qu'on ne le croit !). Naïvement, on pourrait penser que si deux transactions
récupérées lors de différentes synchronisations ont la même date, le même
libellé et le même montant, alors ce sont des doublons. Mais les banques se
permettent de modifier au cours du temps l'une ou plusieurs de ces composantes,
rendant la tâche du gestionnaire de finances personnelles bien plus complexe.
C'est ainsi que des doublons apparaissent : ce sont des paires d'opérations qui
ont tout en commun sauf une composante qui a changé entre deux instantanés pris
sur le site de la banque.&lt;/p&gt;
&lt;p&gt;L'autre souci de CozyPFM est que l'application a été développée sur commande,
par un prestataire qui a ensuite fini sa mission et &lt;em&gt;rendu les clés&lt;/em&gt;. Une fois
la mission du consultant accomplie, l'application passe en mode maintenance, ce
qui signifie que seuls les gros bugs sont corrigés et que celle-ci ne connaît
plus de grandes nouveautés. Quand j'essaie de contribuer au code, je me heurte
à une difficulté, celle-ci technique : l'utilisation d'une technologie que je
ne comprends pas, qui m'impose beaucoup de contraintes pour essayer de
simplifier le développement, et que je n'ai pas envie de faire l'effort
d'apprendre. L'intuition a sonné juste, au vu de l'actuelle désuètude de
l'outil : il s'agissait de la bibliothèque de code JavaScript
&lt;a href="http://backbonejs.org/"&gt;backbone&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="kresus-dhier-a-aujourdhui"&gt;&lt;a class="toclink" href="#kresus-dhier-a-aujourdhui"&gt;Kresus, d'hier à aujourd'hui&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Je m'en souviens encore précisément, c'était juste hier, le 31 juillet 2014,
que j'écris un &lt;a href="https://github.com/bnjbvr/kresus/commit/f458312356ab61f36a0a3193100f18fa436bc1c2"&gt;premier
commit&lt;/a&gt;,
parce que je n'arrive pas à démarrer le serveur  de cozy-pfm. Très vite, je
décide que si je veux pouvoir m'approprier le code, il va falloir de plus
grosses modifications structurelles sur le client Web ; ainsi naquit un fork,
sous le nom de Kresus (pour devenir riche comme
&lt;a href="https://fr.wikipedia.org/wiki/Cr%C3%A9sus"&gt;Crésus&lt;/a&gt; !). S'ensuivent de nombreux
changements, autant dans les choix techniques (réécriture complète du serveur
de CoffeeScript vers du JavaScript moderne, réécriture du client Web avec
React.js, puis plus tard en ajoutant une couche Redux.js) que dans les
fonctionnalités apportées (écran de déduplication manuelle des transactions
bancaires pour palier au problème initial, ajout de la catégorisation, mise en
place de graphiques). D'autres gens sont intéressés, notamment d'autres
personnes qui contribuent à CozyCloud ; je tire parti de l'expérience de la
contribution chez Mozilla pour tâcher d'être chaleureux, remercier ces
inconnu.e.s qui m'offrent des retours, voire des patches, trop content d'avoir
des utilisateur.ice.s.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Capture de Kresus en aout 2018" src="https://bouvier.cc/img/2018-08-kresus.png"&gt;&lt;/p&gt;
&lt;p&gt;Aujourd'hui, quatre ans plus tard, il y a suffisamment de contributeur.i.ces
externes pour que mes deux mains ne suffisent plus à les compter. Il y a une
(tentative de) gouvernance commune du projet. Il y a une gestion du produit
avec une vision plus long terme, même si celle-ci n'est pas toujours clairement
définie. Hey, il y a même un &lt;a href="https://community.kresus.org"&gt;forum&lt;/a&gt; pour que tout
un chacun puisse s'exprimer, et un &lt;a href="https://kresus.org"&gt;site officiel&lt;/a&gt;, avec
son propre &lt;a href="https://kresus.org/blog/"&gt;blog&lt;/a&gt;, que je vous incite à suivre ; mon
blog personnel ne mentionnera Kresus que rarement dorénavant, plutôt sur les
aspects personnels si j'en ressens l'envie. Le travail s'effectue de manière
distribuée, parfois se bloque temporairement, parce que l'on a une vie qui se
déroule en parallèle, et moins de temps libre ; et c'est bien naturel et
entièrement irréprochable !  Les exigences d'un certain niveau de qualité font
que les contributions peuvent mettre du temps à être intégrées. Est-ce que la
conception est cohérente ? Est-ce que les éléments introduits n'interagissent
pas négativement avec d'autres fonctionnalités ? Peut-on généraliser ou
simplifier le besoin ?  Ensuite il faut tester les changements apportés pour
s'assurer que rien d'autre ne casse, vérifier un éventuel impact sur la
réactivité de l'application, jeter un coup d'oeil pour vérifier le rendu et la
réactivité sous mobile. Des corrections peuvent être demandées, pour les plus
prolifiques, démarrant un possible cycle d'aller-retours. Comme le dit la
sagesse populaire : tout seul, on va plus vite ; ensemble, on va plus loin. Il
y a des fonctionnalités dans Kresus auxquelles je n'aurais jamais pensées, il y
a des éléments d'interface bien plus peaufinés que ce que je n'aurais jamais su
faire, il y a des questions de design que je ne me serais jamais posées. Et
c'est tant mieux !&lt;/p&gt;
&lt;h3 id="merci-toi"&gt;&lt;a class="toclink" href="#merci-toi"&gt;Merci, toi !&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Une petite communauté se créé, autour de personnes qui discutent du projet,
décrivent comment l'installer sur son serveur, résolvent des soucis lors de la
mise en place ou de l'utilisation, partagent leurs trucs et astuces. Que ce
soit en utilisant Kresus, en en parlant à des gens autour d'elles et d'eux, en
nous faisant des retours (quand quelque chose se passe mal ou quand quelque
chose pourrait mieux se passer), en nous posant des questions sur les valeurs
et les principes sous-jacents du projet, ou en contribuant au code ou aux
systèmes pour que d'autres puissent l'installer chez eux : vous contribuez
activement à Kresus, et à ce titre je vous remercie personnellement. Vous
faites vivre ce logiciel, c'est par vous qu'il est libre et vous pouvez être
fières et fiers de vos contributions.&lt;/p&gt;
&lt;p&gt;Et si vous avez envie de contribuer également, et que vous avez peur de ne pas
savoir comment faire, détrompez-vous ! Tout le monde a sa pierre à apporter à
un logiciel libre, tout le monde est légitime de poser des questions ou de
présenter ses problématiques ; nous ferons de notre mieux pour les comprendre.
Donc n'hésitez-pas, venez sur le forum, ouvrez un sujet, commentez-en un autre,
essayez Kresus sur le &lt;a href="https://demo.kresus.org"&gt;site de démo&lt;/a&gt; ! Et surtout, si
quelque chose ne fonctionne pas pour vous ou ne vous convient pas,
n'hésitez-pas à venir nous le signaler ! On ne peut travailler sur les défauts
que si on les a clairement identifiés. Et à force de scruter de très (trop)
près le logiciel, on perd parfois le recul nécessaire pour identifier de
bénignes bévues. On a commencé à mettre en place des tests d'expérience
utilisateur.ice, et on a encore beaucoup de chemin à faire. Bref, c'est un
petit geste pour vous, mais pour nous, ça peut vouloir dire beaucoup !&lt;/p&gt;
&lt;p&gt;En conclusion, joyeux anniversaire Kresus, joyeux 4 ans, essayons ensemble de
te faire grandir encore ! Dans les vastes chantiers futurs, nous aimerions
toujours passer à un système d'auto-catégorisation des transactions bancaires,
avoir un meilleur système de dédoublonnage des transactions, trouver d'autres
informations pertinentes à présenter (identifier les transactions récurrentes
et prévoir les soldes négatifs). Et dans les grands plans futurs, il y a
toujours cette volonté de faire voyager Kresus en dehors de France, et donc de
trouver des systèmes pour se brancher sur les banques étrangères ! La route est
longue, mais la banque est libre...&lt;/p&gt;
&lt;p&gt;[1] Le scrapping est une méthode qui permet artificiellement de créer des APIs
pour des sites qui n'en ont pas, en se faisant passer pour un navigateur Web,
en connaissant a priori la structure des pages et en extrayant les données
recherchées. C'est très fragile, mais absolument nécessaire quand il n'y a rien
d'autre (et les banques sont très jalouses de la propriété de leurs données !).&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Thu, 23 Aug 2018 10:00:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2018-08-23:/4-ans-de-kresus-bonjour-kresus-org/</guid><category>blog</category><category>kresus</category></item><item><title>Making calls to WebAssembly fast and implementing anyref</title><link>https://bouvier.cc/mozilla-2018-faster-calls-and-anyref/</link><description>&lt;p&gt;Since this is the end of the first half-year, I think it is a good time to
reflect and show some work I've been doing over the last few months, apart from
the regular batch of random issues, security bugs, reviews and the fixing of 24
bugs found by our &lt;a href="https://en.wikipedia.org/wiki/Fuzzing"&gt;fuzzers&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="bug-1319203-make-js-to-webassembly-calls-blazingly-fast"&gt;&lt;a class="toclink" href="#bug-1319203-make-js-to-webassembly-calls-blazingly-fast"&gt;Bug 1319203: Make JS to WebAssembly calls &lt;em&gt;blazingly&lt;/em&gt; fast&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If we want more WebAssembly (wasm) adoption, there shouldn't be a big costly
barrier between the two universes. That is, calls from one world to the other
should be fast. For a very long time, calls from JS to asm.js/WebAssembly have
been quite slow in Firefox. In fact, we didn't optimize them at all. For ease
and speed of implementation at the time, asm.js call activations (data
structures recording information about the function being currently called in
the VM) were very different from the JS ones. This difference indicated some
significant structural differences, like the capability to reconstruct call
stack information used by &lt;code&gt;Error()&lt;/code&gt; stack frames, or just tracing the stack for
garbage collection purposes. After putting a lot of hard work into refactoring
and low-level changes over the last year, Spidermonkey was finally ripe for an
optimization.&lt;/p&gt;
&lt;p&gt;When we call from JS to asm.js/wasm, the call passes through C++, does a bunch of
work and then calls into a piece of glue code directly written in assembly: the
&lt;em&gt;interpreter entry stub&lt;/em&gt;. This stub is quite small: it just copies out the C++
arguments into the right places the wasm function being called expects, sets up
some small machine state, calls into the function, then does error checking and
eventually returns to the C++ caller. The critical part is JIT compilation. JIT
compilation means that the code is compiled to machine code by the just-in-time
compiler, IonMonkey. When a JS function has been JIT-compiled and it calls into
wasm, then the caller would have to go back to C++ first, before the control
flow is redirected to WebAssembly.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Diagram showing interpreter entry stub" src="https://bouvier.cc/img/2018-07-interpreter-stub.png"&gt;&lt;/p&gt;
&lt;p&gt;Starting with Firefox 60, the JIT compiler makes no distinctions between
calling a JavaScript function or a WebAssembly function, meaning it uses the
same call optimizations for both kinds of function. A new piece of glue code,
the &lt;em&gt;JIT entry stub&lt;/em&gt;, is generated for each exported function: it converts and
unboxes the arguments read from the JIT-compiled JS caller into the right
primitive types as expressed in the wasm function's signature, sets up some
machine registers, calls into the wasm function being called and then converts
the result into a format the JS caller will understand.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Diagram showing JIT entry stub" src="https://bouvier.cc/img/2018-07-jit-stub.png"&gt;&lt;/p&gt;
&lt;p&gt;As you can see, the C++ step that was originally required to call wasm from JS
has been completely eliminated!&lt;/p&gt;
&lt;p&gt;This resulted in massive speedups over a variety of different situations: when
a wasm function is directly / indirectly / polymorphically called, or used as a
getter/setter, or called by &lt;code&gt;Function.prototype.call/apply&lt;/code&gt;, when the call is
missing required arguments, etc. Here's a brief summary of the results, but
there might be a full-blown blog post about these optimizations coming on
&lt;a href="https://hacks.mozilla.org/"&gt;Mozilla Hacks&lt;/a&gt; at some point in the future.
(calling 1 billion times into very simple functions, lower is better)&lt;/p&gt;
&lt;p&gt;&lt;img alt="Charts showing evolution of performance" src="https://bouvier.cc/img/2018-07-wasm-calls.png"&gt;&lt;/p&gt;
&lt;p&gt;This work is not entirely done yet: we can still even better optimize in the
case of a function call from JS when the called wasm function is definitely
known to be a unique wasm target; see the &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1437065"&gt;tracking
bug&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="bug-1422043-lazy-entry-stub-generation"&gt;&lt;a class="toclink" href="#bug-1422043-lazy-entry-stub-generation"&gt;Bug 1422043: Lazy entry stub generation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The previous bug resolution came with an important memory issue: every exported
function now generates a rather big chunk of code for the JIT entry, having an
impact on the memory occupied by the code itself. This would be fine in most
situations where the number of exported functions is generally low. But when
the wasm module exports a Table (think of the equivalent of a C++ function
table with signature checks), we have to assume that every single function,
including those not explicitly exported, needs entry stubs. Indeed, each
function can be eventually called through the Table, after calls to
&lt;a href="http://webassembly.github.io/spec/js-api/index.html#dom-table-set"&gt;WebAssembly.Table.set&lt;/a&gt;.
In fact, the existing code already suffered from this because of the
interpreter entries, but it had been largely amplified by the much larger JIT
entry stubs.&lt;/p&gt;
&lt;p&gt;To fix this, we've decided to lazily generate all the entry stubs for functions
exported through a table. That is, if a function is &lt;em&gt;explicitly&lt;/em&gt; exported, its
stubs will be generated at wasm compile time, but other functions won't have
stubs yet. If a non-exported function is called through a Table, we'll generate
the entry stubs the first time it is called. This involves some fun
interactions with our &lt;a href="https://hacks.mozilla.org/2018/01/making-webassembly-even-faster-firefoxs-new-streaming-and-tiering-compiler/"&gt;tiered
compilation&lt;/a&gt;
mechanism, which can compile functions and create new entry stubs in the
background while the running thread will generate lazy ones.&lt;/p&gt;
&lt;p&gt;Not only this fixed the memory regression introduced by bug 1319203, but it
actually made the situation even better than the baseline, because we didn't
need to generate those interpreter entries for table-exported functions by
default anymore:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Charts showing evolution of memory usage" src="https://bouvier.cc/img/2018-07-wasm-stubs-memory.png"&gt;&lt;/p&gt;
&lt;p&gt;Since it's not entirely readable from the chart: after the patches, the
AngryBots and ZenGarden entry stubs memory usages went down to respectively 262
and 362 KB. This was also a relatively huge win in compilation times, but on
such a low scale that it didn't make a huge difference on total compile time.&lt;/p&gt;
&lt;h2 id="bug-1447591-remove-wasmbinarytotext"&gt;&lt;a class="toclink" href="#bug-1447591-remove-wasmbinarytotext"&gt;Bug 1447591: Remove wasm::BinaryToText&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WebAssembly is a binary format, and there is an equivalent human-readable and
debuggable text format: the WebAssembly Text format, or &lt;em&gt;WAT&lt;/em&gt; format. While
SpiderMonkey once directly produced WAT for display in C++, it's now easier for
&lt;a href="https://github.com/devtools-html/debugger.html"&gt;debugger.html&lt;/a&gt; to do so in JS.
This also made the mapping between bytecode offsets and text offsets (source
maps) more consistent with the display, and it could be useful in other places
where this project is being used. Recently after confirming that the C++
implementation wasn't used anymore, I was able to remove it. It's not every day
that you get a net loss of around 5,500 lines of code, which is always nice:
less code means fewer bugs and less maintenance burden, especially when the code
is dead.&lt;/p&gt;
&lt;h2 id="bug-1445272-1450261-implement-basic-anyref-support"&gt;&lt;a class="toclink" href="#bug-1445272-1450261-implement-basic-anyref-support"&gt;Bug 1445272 / 1450261: Implement basic &lt;code&gt;anyref&lt;/code&gt; support&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A new proposal has been made to the WebAssembly specification committee a few
months ago: to add &lt;a href="https://github.com/WebAssembly/reference-types"&gt;reference
types&lt;/a&gt; to the type system.
Reference types are a new way to represent a reference to any &lt;em&gt;host&lt;/em&gt; values. In
a Web environment, this means being capable of playing with JavaScript values
within WebAssembly. This is a huge difference with the existing type system,
which only contains primitive types: integers represented on 32 or 64 bits,
IEEE754 floating-point numbers represented on 32 or 64 bits. This is also a
first step for implementing &lt;a href="http://github.com/webassembly/gc"&gt;garbage
collection&lt;/a&gt; (GC) integration within
WebAssembly: since these reference values have been allocated on the GC heap in
JavaScript, they need to be traced during wasm execution.&lt;/p&gt;
&lt;p&gt;The basic implementation of this feature in the first bug allows one to use a
new type, called &lt;code&gt;anyref&lt;/code&gt;, as part of a function's signature or in local
variables, be it in a function definition or an imported function. This allows
using JS variables within wasm and pass them around to other JS functions. The
second bug implemented the capability to read and write &lt;code&gt;anyref&lt;/code&gt; values in wasm
Globals [1]. Since Globals can be manipulated outside of the wasm Module thanks
to their JS API, and garbage collections can happen at any time in JS, we
needed to implement GC barriers to make sure that the stored value would not be
marked as unused during tracing. There is good literature explaining why these
barriers are needed and what they do, so I will not expand too much on the
topic.&lt;/p&gt;
&lt;p&gt;Here's an example of usage according to latest spec drafts (and therefore
subject to change for now):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;module&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$alert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;env&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;alert&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;param&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;anyref&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$global_ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;mut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;anyref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ref.null&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;anyref&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;set_and_alert&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;param&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$param&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;anyref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;anyref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;; Put the previous value of $global_ref on the virtual value stack.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;get_global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$global_ref&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;; Get the argument anyref value and store it in $global_ref.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;get_local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$param&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;set_global&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$global_ref&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;; Call the $alert method with the argument anyref value.&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;get_local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$param&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;call&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$alert&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;; The previous value of $global_ref is still on the stack and will be&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;;; returned.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Example of wasm text format using &lt;code&gt;anyref&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;WebAssembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wasmBinary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sb"&gt;`Hello, &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt;!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set_and_alert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;world&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;secretVal&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;42&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// alerts &amp;quot;Hello, world!&amp;quot;, logs null&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;set_and_alert&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;there&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// alerts &amp;quot;Hello, there!&amp;quot;, logs { name: &amp;#39;world!&amp;#39;, secretVal: 42 }&lt;/span&gt;
&lt;span class="p"&gt;})();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Example of JavaScript using the module defined above, passing JS values and
reading them from WebAssembly.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is a very preliminary prototype and it might change in the next few
months. If you feel adventurous, you can try it on Firefox Nightly by setting
the &lt;code&gt;about:config&lt;/code&gt; pref &lt;code&gt;javascript.options.wasm_gc&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt;; note that we
haven't fully hooked this up to garbage collection yet, so your experimentation
might occasionally throw out-of-memory exceptions. In any case, if you see
something, &lt;a href="https://bugzilla.mozilla.org/enter_bug.cgi?product=Core&amp;amp;component=Javascript%3A%20Web%20Assembly"&gt;say
something&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Say you are a compiler developer, and you would like to port your language to
WebAssembly, and your language uses a GC. At the moment, the only way you can
do this is by compiling your garbage collector to WebAssembly, and it would be
backed by the wasm Module's memory. This works, but it won't be very efficient.
Plus, there's already a very efficient, solidly tested, constantly improving
garbage collector in your browser that uses all the possible dirty low-level
tricks known to mankind, which is the GC being used for JavaScript. What if we
could give you access to the garbage collector directly? Then you'd just need
to give a way to define structures, and then could use a set of opcodes to
allocate them, read and write fields on them, etc. At the moment, the reference
types proposal only allows you to move garbage-collected values around. There's
also code in Firefox Nightly to experiment with defining your own data
structures and using them, but it is very very early. If you're interested in
following us implementing more parts, this &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1444925"&gt;tracking
issue&lt;/a&gt; might be of
interest.&lt;/p&gt;
&lt;p&gt;[1] Think of a C++ "global" value, not a JavaScript "global".&lt;/p&gt;
&lt;h2 id="future-work"&gt;&lt;a class="toclink" href="#future-work"&gt;Future work&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is still much more work to be done on the implementation of WebAssembly
in Spidermonkey, to implement other new proposals, to make it faster, or to
have even better generated code.&lt;/p&gt;
&lt;p&gt;A big thank you for the proofreading to &lt;a href="http://whereswalden.com/"&gt;Waldo&lt;/a&gt;,
&lt;a href="https://github.com/steveklabnik"&gt;steveklabnik&lt;/a&gt; and
&lt;a href="https://twitter.com/ag_dubs"&gt;ashleygwilliams&lt;/a&gt;. Extra thanks go to
Ashley who also drew the two diagrams showing how stubs evolved.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Wed, 04 Jul 2018 18:00:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2018-07-04:/mozilla-2018-faster-calls-and-anyref/</guid><category>blog</category><category>compilers</category><category>mozilla</category></item><item><title>Freedom-enabling, not mindless productivity</title><link>https://bouvier.cc/freedom-enabling-productivity/</link><description>&lt;p&gt;&lt;img alt="Freedom-enabling, not mindless productivity" src="https://bouvier.cc/img/2017-12-11_keep-exploring.jpg"&gt;&lt;/p&gt;
&lt;p&gt;There are many self-development articles out there on blogs, detailing all the
techniques and methods that one can use to work better, be happier, become more
successful, whatever you can dream of. It really feels like these techniques
can all be reduced to a well-defined set of core habits. Work out.  Practice
journaling. Meditate. Be grateful. Read a lot. Drink a liter of water every
day. Alright, you get the idea; if you're reading this you probably went
through a whole lot of other very similar self help posts in the past. Or even
read books about the topic. However, those can easily be misinterpreted. Let's
find out how. This post is mostly an open-mind manifesto, with some principles
that might be obvious to some, but for others they might help ease the mind and
relax.&lt;/p&gt;
&lt;h2 id="if-all-you-have-is-a-todo-list-everything-looks-like-a-task"&gt;&lt;a class="toclink" href="#if-all-you-have-is-a-todo-list-everything-looks-like-a-task"&gt;If all you have is a todo-list, everything looks like a task&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Have you ever bought a self-development book and read through the ratings
section right within the book? It is often placed at the beginning, and it is a
convincing marketing way to make sure your readers get hooked from the start.
It gives credibility too; look at all these random people who confirm the
effectiveness of what you're about to read, before you actually know what
they're talking about. They expand on how their life changed when they used a
particular technique, and how they are applying it to every field of their life,
how they feel much better now than other people around them, and how they
astonished their friends and family by causing a radical change in their life.&lt;/p&gt;
&lt;p&gt;I think this is the reason why so many of these books are put aside by most
people, who materialize an interesting objection: this is the formula for a
sect-like cult. Is it this stunning that we talk about productivity gurus in
the first place? Let's think about it for a second: these comments seem to
suggest that our whole world generates a wide range of different issues that
can all be addressed with a low number of solutions. You can take any problem
in your life, turn it in one particular way so as to see it through the lenses
of this new method, and solve it one way or the other. Every problem can be
solved with a single technique. This can be the source of a confirmation bias:
if you want it badly enough, and try long enough, you can be pretty sure that
any issues can fit the scope of that given method you're experimenting with.&lt;/p&gt;
&lt;p&gt;In my opinion, this excess can be harmful. In fact, if we'd try to draw a
parallel with politics, I'd say these look like the premises for a fascist
regime (note I am not a historian, so this might be incomplete according to my
high-school memories). Indeed, some of it is there: providing the same answer
to all public issues (thus re-branding them, which can be facilitated by
designating scapegoats), forcing one into adopting behavior that might not be
suited for them, having a clear distinction between us (who have access to The
Solution) versus them (who don't/can't have access to it), setting up a cult of
the personality towards the author of The Solution.&lt;/p&gt;
&lt;p&gt;Why would we act like this? I am no sociologist, and there are probably many
reasons, but we can explore some basic ideas: maybe &lt;em&gt;some&lt;/em&gt; people feel
powerless when facing the complexity of a world where everything is intertwined
in so many ways and evolving at a very high pace. Having a unique, predefined,
seemingly theoretically proven answer provides them with some sense of order
and intellectual easiness. On one side, whole ranges of issues then get easily
resolved and put aside, which gives head space for other matters; on the other
side, it means that there are no conflicts in thinking, less freedom of choice,
no attempts to solutions that are more suited to different groups and contexts,
and which ultimately could be better overall. Last but not least, it also mean
this group could be wrong, remain stuck with their opinions and get away with
them. But while being a huge one, that's just one pain point of productivity.
What else is wrong?&lt;/p&gt;
&lt;p&gt;There's another common objection that I call the fallacies of mimicry: as
if by imitating the actions and habits of so-called successful people, you
could get their success too. Warren Buffet reads a lot of hours a day; he is
insanely rich; so if I read a lot of hours a day, then I'll become rich,
somehow, right? I think this kind of reasoning is completely flawed, as it
inverts the consequences with the premises. Notably, when you get successful
enough (which seems to translate here by "you don't have to worry about money
anymore"), you get this great amount of free time that gives you the
possibility to read. There's another quirk in that thinking: different
methods, techniques, habits apply to different people in different contexts,
and there's no one unique solution that works for all. So repeating the actions
of others might not be suited for your particular situation, and it could show
useless.&lt;/p&gt;
&lt;p&gt;This also raises another point I wonder about: is the seek of productivity only
a topic for the privileged? If you consider something like &lt;a href="https://en.wikipedia.org/wiki/Maslow's_hierarchy_of_needs"&gt;Maslow's hierarchy
of needs&lt;/a&gt;,
productivity would probably belong to the highest level (self-actualization),
since it assumes all other issues in your life have been addressed first. If we
put aside the working life aspect, a great amount of knowledge can also apply
to one's personal life and free time. Yet, it feels it's a sign that "success"
compounds, to some extent: the less you have to worry about universal basic
needs, the more you can have time to read, learn, get better and enhance
yourself, which in turn makes you more suited to reach whatever goal you aim
for, thus becoming even more successful. It doesn't only happen with
productivity, but also for instance with education: kids from richer families
tend to perform better than kids from poorer families, etc. (there are studies
that back this theory up, and of course I can't find links back to them).&lt;/p&gt;
&lt;p&gt;So we've identified issues related to productivity methods. But let's not throw
the baby out with the bath water. There has to be a way to make value out of
it. How can we get past these problems?&lt;/p&gt;
&lt;h2 id="to-seek-the-whys"&gt;&lt;a class="toclink" href="#to-seek-the-whys"&gt;To seek the whys&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There's always something else that's tickling me about those posts: they seem
to confound the means and the ends. Being productive isn't an end per se, it is
a tool. And it seems that people forget what is their own motivation in the
first place, what is their &lt;em&gt;why&lt;/em&gt;. Why do you want to be more productive or
successful anyways? Do you want to work less? Or to spend more time with your
friends and family? Or to spend more time on hobbies and passions that can make
you feel more fulfilled? Or is your motivation entirely different, and you want
to raise up in your company's hierarchy, by rising up your throughput, the
quantity and quality of your work? All motives are valid here of course. But
there should be one in the first place, otherwise motivation might not quite
follow, and thus the practice of routines will be aborted very soon after they
get started. This is often a very strong sign for myself, when I consider doing
something, add it to a todo-list and months later it is still there; maybe it
wasn't that useful or valuable, and I can erase it with a light heart.&lt;/p&gt;
&lt;p&gt;And when the initial, kickstarting motivation is right there, the &lt;em&gt;why&lt;/em&gt; should
also help set a limit to the endless quest of productivity. To know when to
stop. For instance, when you managed to get more time for a dedicated hobby,
and you're plain satisfied, what would be the point of squeezing even more in
your limited free time? Remember, productivity is a means to an end, not an end
by itself. Without this in mind, you could be chasing an endless goal and
wanting always more work. But enough is enough.&lt;/p&gt;
&lt;p&gt;People get easily fooled into thinking that more working hours imply more
quality work. That's a societal feeling: in a capitalistic society, being
productive means contributing to growth thus the good economic health of an
entity greater than yourself (your country, your region, the world). And since
people mix up being productive with working long hours, the confusion is easy
to make. But I think productivity is quite the opposite of this. I think this
is about &lt;strong&gt;trying to work the least number of hours to advance work on the most
important and valuable things&lt;/strong&gt;. To be maximally efficient with the minimum
amount of resources. Identify those actions which will have the most positive
impact, help the greatest number of people, be &lt;em&gt;valuable&lt;/em&gt;. So this is another
opportunity to acknowledge the need for a why: why do you work, in the first
place? Is the work you're doing valuable, or are you doing busy work (like
handling emails, answering very quickly on instant chat systems, etc.) to make
it &lt;em&gt;look like&lt;/em&gt; you're productive? Or more humbly, one might just be working to
get the occasional pay check, since work doesn't have to be a source of
fulfillment, but instead can just be a means to an end too. Again, all motives
are good here; but there should be one to make sense out of it.&lt;/p&gt;
&lt;p&gt;Also, blocking time for rest and non-work activities is critical; neuroscience
has proven that the brain mostly works under two modes, a focused mode (when we
consciously think about or work on a given problem) and a diffused mode (that
gets triggered whenever we rest, do errands). Getting stuck in one of the two
is the best way to miss better solutions or do subefficient work. It seems
probably obvious to most that the former is needed, but a lot of people tend to
underestimate the usefulness of the latter. A lot of background processing
happens in this mode, and creative solutions can emerge out of this mind
state: this might have happened to you through dreams, reveries, showers or
workout breakthroughs, for instance.&lt;/p&gt;
&lt;h2 id="to-do-what-you-want-to-want-what-you-do"&gt;&lt;a class="toclink" href="#to-do-what-you-want-to-want-what-you-do"&gt;To do what you want, to want what you do&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Despite the apparent logical inversion, I think there's something that makes
habit recommendations very appealing; in the end, it's not about reproducing
these success stories but much more about having a high-end lifestyle, in which
you &lt;em&gt;take&lt;/em&gt; time for some particular actions and habits, instead of feeling that
you &lt;em&gt;lack&lt;/em&gt; time for these. It is much more about being conscious of what really
matters to you, what you really want to do, rather than getting rich and
famous.&lt;/p&gt;
&lt;p&gt;I state that the following is one goal of productivity: to be more aware of all
the choices we're making (what to work on) so that our work is more in
adequation with our principles and real objectives. The definition of work here
is larger than just a job: it could be any activity one practices on their
time. Thus it is about freedom, that is, the way to express what you truly
desire to do and then to do it with purpose. Or in the words of French writer
and journalist Françoise Giroud: happiness is doing what you want, and wanting
what you do. I think other people call this autonomy or integrity; I hope
you get the idea.&lt;/p&gt;
&lt;p&gt;In particular, I don't want others to preconceive life choices for myself. Even
if they have theorized the topic and proven with objective metrics that it
worked for them. So here is my meta-productivity advice: to &lt;strong&gt;try different
methods, to make your own solutions out of them, to choose what works according
to the context&lt;/strong&gt;. Even if I need to spend a lot of time on thinking things
through first, before applying my own crafted solutions, it is such a lower
entry cost than doing erratic stuff without purpose and realize later I lost my
time. Of course, I might not find the best solution on the first try, but
that's alright. It might mean I switch routines from one week to the other, or
I don't have a consistent agenda; that is okay. I can experiment with many
possible ways to do one thing, according to my current context: my state of
mind, geographical location, needs, expectations, levels of energy, unexpected
events popping up throughout the day, political context, really anything. As
long as everything I do is conscious, works for me and makes me feel more
fulfilled, I'll choose the trade-off of not having perfect control and a
predefined answer to everything.&lt;/p&gt;
&lt;p&gt;What some call the (self) review process matters here: one has to make sure
they're doing their own Right Thing, in terms of process and goals, at periodic
intervals. Otherwise, there's a risk to get drawn in the froth of the days,
lose sight on what truly matters to us and get lost. During this process, it is
important to pretend you're an external observer to yourself, so as to avoid
falling into judgement and then feeling overwhelmed or unhappy with yourself.
You can for instance consider you're a scientific researcher that just tries to
assess hypothesis and confront them with the reality. Or anything else really;
as long as you keep it fun!&lt;/p&gt;
&lt;p&gt;With this in mind, productivity has been much less stressful to me, and much
more of an experimental journey. It has ceased being a tyrant always claiming
for more of my time and it now feels more like a companion in the quest for
happiness.&lt;/p&gt;
&lt;p&gt;A huge thank you to &lt;a href="http://jan.tools"&gt;Jan Keromnes&lt;/a&gt; and &lt;a href="http://adrian.gaudebert.fr/"&gt;Adrian
Gaudebert&lt;/a&gt; for proof-reading this and suggesting
improvements.&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href="https://unsplash.com/photos/Gcl6jcB1r9g"&gt;Justin Luebke&lt;/a&gt; on
&lt;a href="https://unsplash.com/"&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Mon, 11 Dec 2017 09:00:00 +0100</pubDate><guid isPermaLink="false">tag:bouvier.cc,2017-12-11:/freedom-enabling-productivity/</guid><category>blog</category><category>life</category></item><item><title>Kresus: version 0.11.0</title><link>https://bouvier.cc/kresus-version-0-11-0/</link><description>&lt;p&gt;L'équipe vient de publier une nouvelle version de &lt;a href="https://kresus.org"&gt;Kresus&lt;/a&gt;,
un gestionnaire libre de finances personnelles sur lequel je travaille. Pour
rappel, cette application web, basée sur &lt;a href="http://weboob.org/"&gt;Weboob&lt;/a&gt; et
disponible &lt;a href="https://www.karolak.fr/blog/2016/03/18/kresus-un-gestionnaire-web-de-finances-personnelles/"&gt;de manière
autonome&lt;/a&gt;
ou dans &lt;a href="https://cozy.io/"&gt;CozyCloud&lt;/a&gt;, vous permet de vous connecter à votre
compte bancaire, de récupérer vos opérations et de les classifier pour savoir
comment vous dépensez votre argent afin de mieux maîtriser vos finances.&lt;/p&gt;
&lt;h2 id="en-resume"&gt;&lt;a class="toclink" href="#en-resume"&gt;En résumé&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;De nouvelles banques, une expérience utilisateur encore améliorée, un
chargement initial un peu plus rapide, plus de stabilité pour la récupération
des données bancaires, et des simplifications pour l'auto-hébergement au
sommaire de cette version mineure !&lt;/p&gt;
&lt;h3 id="nouvelles-banques-et-support-de-weboob"&gt;&lt;a class="toclink" href="#nouvelles-banques-et-support-de-weboob"&gt;Nouvelles banques et support de Weboob&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Kresus s'appuie sur les épaules du logiciel libre &lt;a href="http://weboob.org"&gt;Weboob&lt;/a&gt;
pour récupérer les données bancaires.&lt;/p&gt;
&lt;p&gt;La version minimale de weboob pour utiliser Kresus est maintenant la &lt;strong&gt;version
1.2&lt;/strong&gt;. Cependant, comme nous avons observé que de plus en plus de modules
bancaires ne fonctionnent plus en version 1.2, nous recommandons d’installer la
version de développement pour profiter des mises à jour continues.&lt;/p&gt;
&lt;p&gt;Nous avons ajouté le support pour les nouvelles entités bancaires que Weboob
supporte désormais :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Laydernier et Société Marseillais de Crédit (groupe Crédit du Nord)&lt;/li&gt;
&lt;li&gt;Les comptes professionnels du Crédit Mutuel de Bretagne&lt;/li&gt;
&lt;li&gt;Le Crédit Mutuel du Massif Central&lt;/li&gt;
&lt;li&gt;BTP Banque&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Le support des épargnes salariales a été largement augmenté également :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prado Epargne&lt;/li&gt;
&lt;li&gt;Crédit Mutuel Epargne Salariale&lt;/li&gt;
&lt;li&gt;CIC Epargne Salariale&lt;/li&gt;
&lt;li&gt;BNP Epargne Salariale&lt;/li&gt;
&lt;li&gt;Axa Epargne Salariale&lt;/li&gt;
&lt;li&gt;Société Générale Epargne Salariale&lt;/li&gt;
&lt;li&gt;HSBC Epargne Salariale&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Par ailleurs, le module S2E (qui gère les plans épargne entreprises de
plusieurs banques) a été supprimé ; les accès actuellement configurés seront
migrés automatiquement vers les modules bancaires appropriés.&lt;/p&gt;
&lt;h3 id="amelioration-de-linterface-utilisateur-et-de-lexperience-utilisateur"&gt;&lt;a class="toclink" href="#amelioration-de-linterface-utilisateur-et-de-lexperience-utilisateur"&gt;Amélioration de l'interface utilisateur et de l'expérience utilisateur&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Notre travail sur l'interface et l'expérience utilisateur continue :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Il est maintenant possible de cacher le menu, indépendemment de la taille de
  l'écran (ce n’était possible que sur mobile jusqu’à présent).&lt;/li&gt;
&lt;li&gt;Les dates sont enfin affichées de manière homogène entre les navigateurs, en
  fonction de la langue choisie par l’utilisateur.&lt;/li&gt;
&lt;li&gt;Les sélecteurs ont été stylisés pour s’afficher de manière uniforme dans tous
  les navigateurs.&lt;/li&gt;
&lt;li&gt;Les graphiques utilisent maintenant les mêmes couleurs que la page de
  rapport.&lt;/li&gt;
&lt;li&gt;Les sélecteurs de type et catégories dans la vue des opérations s'ouvrent dès
  le premier clic.&lt;/li&gt;
&lt;li&gt;Beaucoup de corrections de vocabulaire, d'erreurs de typographie et
  d’affichage.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Kresus se chargera également plus rapidement, dorénavant ! Le client a été
allégé en supprimant plusieurs dépendances peu usitées et en minifiant les
fichiers de code, diminuant la taille totale des fichiers que le navigateur
doit charger, ce qui implique un chargement plus rapide. Ce nettoyage des
dépendances s'accompagne d'un travail d'intégration de toutes ces dernières
sous forme de paquets npm. Ceci permettra un suivi plus fin de la mise à jour
de ces dépendances.&lt;/p&gt;
&lt;h3 id="stabilite"&gt;&lt;a class="toclink" href="#stabilite"&gt;Stabilité&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Côté serveur, l’import des opérations a été amélioré de manière à s’assurer du
bon séquencement de toutes les opérations asynchrones (import de comptes puis
d’opérations). Ceci devrait régler plusieurs problèmes observés d'imports
multiples, d'opérations allouées aux mauvais comptes etc.&lt;/p&gt;
&lt;h3 id="auto-hebergement"&gt;&lt;a class="toclink" href="#auto-hebergement"&gt;Auto-hébergement&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Il est maintenant possible d’héberger Kresus autrement qu’à la racine d’un
domaine (par exemple &lt;code&gt;https://mondomaine.fr/kresus&lt;/code&gt;). Pour cela, il faut passer
la variable d'environnement &lt;code&gt;KRESUS_URL_PREFIX&lt;/code&gt; à l'application. Cette variable
désigne le chemin d'accès depuis la racine (&lt;code&gt;/kresus&lt;/code&gt; dans l'exemple).&lt;/p&gt;
&lt;p&gt;Le Dockerfile a été amélioré pour couvrir de plus nombreuses dépendances des
modules bancaires par défaut.&lt;/p&gt;
&lt;h3 id="le-mot-de-la-fin"&gt;&lt;a class="toclink" href="#le-mot-de-la-fin"&gt;Le mot de la fin&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Merci à tous les contributeurs, et en particulier aux hyperactifs
&lt;a href="https://nicofrand.eu"&gt;nicofrand&lt;/a&gt; et &lt;a href="https://github.com/ZeHiro"&gt;ZeHiro&lt;/a&gt; pour
avoir écrit ce billet et pour leurs très nombreuses contributions !&lt;/p&gt;
&lt;p&gt;Comme d'habitude, si vous avez des remarques ou suggestions, n'hésitez-pas à
nous le faire savoir, sur &lt;a href="https://tutut.delire.party/@kresus"&gt;mastodon&lt;/a&gt;,
&lt;a href="https://twitter.com/kresusapp"&gt;twitter&lt;/a&gt;, le &lt;a href="https://kiwiirc.com/client/chat.freenode.net/kresus"&gt;canal
IRC&lt;/a&gt;, la &lt;a href="https://framalistes.org/sympa/info/kresus"&gt;liste de
diffusion&lt;/a&gt;, ou encore
&lt;a href="https://framasphere.org/people/315a5640ead10132c4cc2a0000053625"&gt;diaspora&lt;/a&gt;  !&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Sat, 06 May 2017 20:30:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2017-05-06:/kresus-version-0-11-0/</guid><category>blog</category><category>kresus</category></item><item><title>Kresus: version 0.10.0</title><link>https://bouvier.cc/kresus-version-0-10-0/</link><description>&lt;p&gt;L'équipe de Kresus vient de publier une nouvelle version de
&lt;a href="https://framagit.org/bnjbvr/kresus/"&gt;Kresus&lt;/a&gt;, un gestionnaire libre de
finances personnelles sur lequel je travaille. Pour rappel, cette application
web, basée sur &lt;a href="http://weboob.org/"&gt;Weboob&lt;/a&gt; et disponible &lt;a href="https://www.karolak.fr/blog/2016/03/18/kresus-un-gestionnaire-web-de-finances-personnelles/"&gt;de manière
autonome&lt;/a&gt;
ou dans &lt;a href="https://cozy.io/"&gt;CozyCloud&lt;/a&gt;, vous permet de vous connecter à votre
compte bancaire, de récupérer vos opérations et de les classifier pour savoir
comment vous dépensez votre argent afin de mieux maîtriser vos finances.&lt;/p&gt;
&lt;h2 id="en-resume"&gt;&lt;a class="toclink" href="#en-resume"&gt;En résumé&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cette nouvelle version apporte de nombreuses améliorations de l'interface
utilisateur et met à niveau la version autonome (en dehors de Cozy) en termes
de fonctionnalités. Merci aux 3 contributeurs de cette nouvelle version, et
aux &lt;a href="https://framagit.org/bnjbvr/kresus/compare/bf048fca9687f139d1a1d670bec0b5ac138448ce...906ffac4d341b4e08bfda9bebe68cf86d1cd29c6"&gt;80
commits&lt;/a&gt;
effectués, pour un total de 151 fichiers modifiés, avec 2080 ajouts et 1406
suppressions de lignes de code !&lt;/p&gt;
&lt;h3 id="nouvelles-banques"&gt;&lt;a class="toclink" href="#nouvelles-banques"&gt;Nouvelles banques&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Kresus s'appuie sur les épaules du logiciel libre &lt;a href="http://weboob.org/"&gt;Weboob&lt;/a&gt;
pour récupérer les données bancaires. Nous avons donc ajouté le support pour
les nouvelles entités que Weboob supporte désormais : la banque &lt;em&gt;Nuger&lt;/em&gt; (groupe
&lt;em&gt;Crédit du Nord&lt;/em&gt;) et l'assurance vie &lt;em&gt;Spirica&lt;/em&gt; (groupe &lt;em&gt;Crédit Agricole&lt;/em&gt;).&lt;/p&gt;
&lt;h3 id="version-autonome"&gt;&lt;a class="toclink" href="#version-autonome"&gt;Version autonome&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Suite aux &lt;a href="https://blog.cozycloud.cc/post/2016/11/21/En-route-vers-Cozy-version-3?lang=fr"&gt;récentes
décisions&lt;/a&gt;
de l'équipe CozyCloud, et aux changements techniques qui en résultent, cette
version de Kresus pourrait être la dernière à fonctionner avec Cozy. Cependant,
rien de grave ! D'une part, Kresus continuera de fonctionner tant que la mise à
jour vers la version 3 de Cozy n'aura pas eu lieu. D'autre part, nous mettons
tout en œuvre pour que la version autonome de Kresus, c'est-à-dire celle qui
peut se lancer sans Cozy, soit la plus simple à installer et la plus
fonctionnelle possible, afin que la transition soit très simple.  Par ailleurs,
nous cherchons de l'aide pour &lt;a href="https://framagit.org/bnjbvr/kresus/issues/515"&gt;empaqueter
Kresus&lt;/a&gt; dans YunoHost, à bon
entendeur :-)&lt;/p&gt;
&lt;p&gt;Pour cela, voici quelques améliorations apportées dans cette version :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Il est désormais possible de changer la langue d'utilisation de Kresus dans
  la version autonome, au grand bonheur des francophones, puisque la langue par
  défaut était celle de Shakespeare.&lt;/li&gt;
&lt;li&gt;Il est désormais possible de configurer un relais SMTP, afin que Kresus
  puisse envoyer des emails. Les utilisateurs de la version autonome pourront
  désormais profiter des alertes et des rapports emails ! Pour cela, allez dans
  la section des Préférences, puis Alertes, et dépliez le petit panneau de
  "Configuration" pour régler les paramètres du relais SMTP.&lt;/li&gt;
&lt;li&gt;Le fichier README (Lisez-moi, pour les puristes) a été partiellement revu et
  mis à jour, pour correspondre plus précisément au processus d'installation.
  Installer Kresus en mode autonome est aussi simple qu'installer Weboob et
  exécuter &lt;code&gt;npm install -g kresus&lt;/code&gt; en ligne de commande !&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="amelioration-de-linterface-utilisateur-et-de-lexperience-utilisateur"&gt;&lt;a class="toclink" href="#amelioration-de-linterface-utilisateur-et-de-lexperience-utilisateur"&gt;Amélioration de l'interface utilisateur et de l'expérience utilisateur&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Désormais, tous les comptes sont affichés depuis le menu, ainsi que le solde
  total des comptes associés à la banque en question, le tout dans une
  interface plus légère et plus simple.&lt;/li&gt;
&lt;li&gt;Les graphiques ont également subi un coup de peinture,  notamment les
  graphiques qui représentent des données sur de longues périodes, pour
  lesquels les labels ne se chevaucheront désormais plus. La sélection des
  types d'entrées (crédits, débits, ou les deux) pour le graphique par
  catégorie a également été simplifiée. Vous pouvez désormais sélectionner le
  graphique à afficher par défaut, en utilisant le menu de préférences intégré.&lt;/li&gt;
&lt;li&gt;La section des paramètres a été simplifiée, et les paramètres par défaut sont
  désormais accessibles depuis les sections qui les concernent. Toujours dans
  les paramètres, les IBANs sont désormais affichés plus proprement.&lt;/li&gt;
&lt;li&gt;La saisie des montants, lors de recherches, dans les budgets ou lors d'un
  ajout manuel d'opérations, a également été revue, puisqu'une icône de signe
  accompagne désormais les montants entrés par l'utilisateur.&lt;/li&gt;
&lt;li&gt;C'est bientôt le printemps, et la liste des opérations commence déjà à
  rayonner de couleurs ! En effet, chaque opération assignée à une catégorie
  revêtira la couleur associée à cette catégorie.&lt;/li&gt;
&lt;li&gt;Dans la section &lt;em&gt;Doublons&lt;/em&gt;, vous pouvez désormais vérifier le libellé
  personnalisé d'une opération, en plus de son libellé bancaire, en survolant
  l'icône &lt;em&gt;?&lt;/em&gt; afin de vous ôter tout doute.&lt;/li&gt;
&lt;li&gt;Dans la section &lt;em&gt;Budget&lt;/em&gt;, les seuils négatifs sont désormais possibles et
  deux nouvelles possibilités d'affichage font leur apparition : la vue en
  pourcentages et le fait de pouvoir cacher les catégories sans seuils.&lt;/li&gt;
&lt;li&gt;La synchronisation des comptes d'une banque envoie beaucoup moins de données
  sur le réseau et est plus fluide à l'affichage.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="mobile"&gt;&lt;a class="toclink" href="#mobile"&gt;Mobile&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Plusieurs améliorations ont été apportées pour rendre l'application plus accessible sur mobile :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Le défilement vertical est désormais utilisable dans le menu.&lt;/li&gt;
&lt;li&gt;Les marges et espaces vides entre les différents blocs ont été réduits et
  optimisés.&lt;/li&gt;
&lt;li&gt;L'affichage du solde, des dépenses, revenus et balance est réorganisé sous
  forme de damier au lieu de quatre lignes.&lt;/li&gt;
&lt;li&gt;Des menus déroulants sont utilisés pour les sous-menus des sections
  paramètres et graphiques au lieu des menus hamburgers.&lt;/li&gt;
&lt;li&gt;Les champs du formulaire de recherche ont été réagencés pour être plus
  lisibles.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="nouvelles-fonctionnalites"&gt;&lt;a class="toclink" href="#nouvelles-fonctionnalites"&gt;Nouvelles fonctionnalités&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Pour les utilisateurs de Cozy, une notification est émise par compte
  bancaire, et non plus par accès à une banque. Lorsqu'une seule opération a
  été importée, son montant est directement affiché dans la notification.&lt;/li&gt;
&lt;li&gt;Il arrive que les informations liées aux comptes bancaires changent au cours
  du temps (par exemple, le libellé d'un compte peut changer), impliquant des
  problèmes de doublons au sein de Kresus. Désormais, un algorithme efficace de
  détection de comptes en double a été implémenté, et les comptes ne devraient
  plus être mélangés. Le prochain chantier sur le sujet concerne une meilleure
  détection automatique des opérations en double.&lt;/li&gt;
&lt;li&gt;La gestion de Weboob a été améliorée : les erreurs sont désormais mieux
  indiquées, mieux gérées et plus explicites. Les mises à jours des modules
  sont également plus robustes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="le-mot-de-la-fin"&gt;&lt;a class="toclink" href="#le-mot-de-la-fin"&gt;Le mot de la fin&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Merci à tous les contributeurs, et en particulier aux hyperactifs
&lt;a href="https://nicofrand.eu"&gt;nicofrand&lt;/a&gt; et &lt;a href="https://github.com/ZeHiro"&gt;ZeHiro&lt;/a&gt; pour
avoir participé à l'écriture de ce billet et pour leurs très nombreuses
contributions !&lt;/p&gt;
&lt;p&gt;Comme d'habitude, si vous avez des remarques ou suggestions, n'hésitez-pas à
nous le faire savoir, par &lt;a href="https://twitter.com/kresusapp"&gt;twitter&lt;/a&gt;, le &lt;a href="https://kiwiirc.com/client/chat.freenode.net/kresus"&gt;canal
IRC&lt;/a&gt;, la &lt;a href="https://framalistes.org/sympa/info/kresus"&gt;liste de
diffusion&lt;/a&gt;, ou encore
&lt;a href="https://framasphere.org/people/315a5640ead10132c4cc2a0000053625"&gt;diaspora&lt;/a&gt;  !&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Mon, 20 Feb 2017 11:00:00 +0100</pubDate><guid isPermaLink="false">tag:bouvier.cc,2017-02-20:/kresus-version-0-10-0/</guid><category>blog</category><category>kresus</category></item><item><title>Kresus: version 0.9.0</title><link>https://bouvier.cc/kresus-version-0-9-0/</link><description>&lt;p&gt;L'équipe de Kresus vient de publier une nouvelle version de
&lt;a href="https://framagit.org/bnjbvr/kresus/"&gt;Kresus&lt;/a&gt;, un gestionnaire de finances
personnelles open-source sur lequel je travaille. Pour rappel, cette
application, basée sur &lt;a href="http://weboob.org/"&gt;Weboob&lt;/a&gt;, est disponible dans
&lt;a href="https://cozy.io/en/"&gt;CozyCloud&lt;/a&gt; ou
&lt;a href="https://www.karolak.fr/blog/2016/03/18/kresus-un-gestionnaire-web-de-finances-personnelles/"&gt;en dehors&lt;/a&gt;
et vous permet de vous connecter à votre compte bancaire, récupérer vos
opérations et les classifier pour savoir où votre argent passe.&lt;/p&gt;
&lt;h3 id="kresus-utilise-des-nouveaux-moyens-de-communication-son-facteur-le-deteste-decouvrez-son-secret"&gt;&lt;a class="toclink" href="#kresus-utilise-des-nouveaux-moyens-de-communication-son-facteur-le-deteste-decouvrez-son-secret"&gt;Kresus Utilise Des Nouveaux Moyens De Communication, Son Facteur Le Déteste, Découvrez Son Secret&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Kresus prend son envol et a désormais un
&lt;a href="https://kresus.org"&gt;site web officiel&lt;/a&gt; avec une section Foire Aux Questions en
construction ! Des nouveaux moyens de communication ont également été mis en
place : en plus du classique &lt;a href="https://kiwiirc.com/client/chat.freenode.net/kresus"&gt;canal
IRC&lt;/a&gt; déjà existant, une
&lt;a href="https://framalistes.org/sympa/info/kresus"&gt;liste de diffusion&lt;/a&gt; a été ouverte
pour les annonces de mises à jour, mais aussi pour faciliter le support à
toutes les étapes, lors de l'installation ou de l'utilisation quotidienne de
Kresus. N'hésitez-pas à vous
&lt;a href="https://framalistes.org/sympa/subscribe/kresus"&gt;inscrire&lt;/a&gt; ! Pour des
interactions plus courtes et pour rester au courant des nouveautés, un
&lt;a href="https://twitter.com/kresusapp"&gt;compte twitter&lt;/a&gt; a également été ouvert,
n'hésitez-pas à nous envoyer des remarques courtes ou vos messages d'amour, ça
fait toujours plaisir ;-)&lt;/p&gt;
&lt;h3 id="les-nouveautes-de-cette-version"&gt;&lt;a class="toclink" href="#les-nouveautes-de-cette-version"&gt;Les nouveautés de cette version&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Un grand merci aux 4 contributeurs de cette nouvelle version, pour un total de 62 commits !&lt;/p&gt;
&lt;h4 id="nouvelles-banques"&gt;&lt;a class="toclink" href="#nouvelles-banques"&gt;Nouvelles banques&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;De nombreux nouveaux modules bancaires ont été intégrés dans Kresus :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Amundi&lt;/li&gt;
&lt;li&gt;AFER&lt;/li&gt;
&lt;li&gt;Banque de Savoie&lt;/li&gt;
&lt;li&gt;Crédit agricole Épargne Longue des Salariés&lt;/li&gt;
&lt;li&gt;Crédit du nord Plan Épargne Entreprise&lt;/li&gt;
&lt;li&gt;Number26&lt;/li&gt;
&lt;li&gt;Yomoni&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="budget"&gt;&lt;a class="toclink" href="#budget"&gt;Budget&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Vous pouvez désormais évaluer vos dépenses pour un compte donné, catégorie par
catégorie, et savoir si vous avez dépassé le budget alloué à une catégorie pour
le mois ou combien il vous reste à dépenser.  Il suffit pour ça d'affecter dans
la nouvelle section "Budget" un budget à chaque catégorie et le calcul se fera
automatiquement. Pour vérifier vos transactions des mois précédents, modifiez
la période souhaitée.  Pour accéder rapidement aux transactions affectées à une
catégorie pour la période sélectionnée, cliquez sur l'icône "Recherche".&lt;/p&gt;
&lt;h4 id="interface-et-experience-utilisateur"&gt;&lt;a class="toclink" href="#interface-et-experience-utilisateur"&gt;Interface et expérience utilisateur&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;La section "Catégories" a été revue pour une utilisation plus simple et
  rapide : vous pouvez désormais directement modifier le titre d'une catégorie
  sans cliquer sur le bouton "Éditer".&lt;/li&gt;
&lt;li&gt;La section "À propos" située jusqu'ici dans la section "Préférences" a été
  déplacée dans le menu, tout en bas. Par défaut repliée, cliquez sur la ligne
  tout en bas du menu pour ouvrir cette section et accéder aux raccourcis vers
  le site web de Kresus, la license, le code source ou encore le blog.&lt;/li&gt;
&lt;li&gt;Lorsque vous ajoutez Kresus à l'écran d'accueil de votre smartphone, celui-ci
  est détecté comme une application web et la barre de navigation du navigateur
  est automatiquement cachée afin de gagner de l'espace (si votre navigateur le
  supporte).&lt;/li&gt;
&lt;li&gt;L'affichage des détails d'une opération se fait dans une modale sur un
  navigateur de bureau.&lt;/li&gt;
&lt;li&gt;Les types d'opérations sont désormais triés dans l'ordre alphabétique.&lt;/li&gt;
&lt;li&gt;Lorsque vous demandez à effectuer une opération qui prend du temps (comme
  importer un nouveau compte), des écrans d'attente vous sont désormais
  affichés, vous prévenant qu'il est normal que l'opération prenne un peu de
  temps. Un des plus gros problèmes d'expérience utilisateur (et un des plus
  vieux trolls du canal IRC de CozyCloud) est ainsi réglé !&lt;/li&gt;
&lt;li&gt;Il est désormais possible de naviguer au clavier dans la liste des opérations
  afin de modifier le type, l'intitulé ou la catégorie. Pour déplier le menu
  déroulant, il suffit d'appuyer sur la touche espace de votre clavier et de
  sélectionner le bon type/catégorie avec les flèches et valider par la touche
  entrée.&lt;/li&gt;
&lt;li&gt;Dans la section "Doublons", il est désormais possible de trouver facilement
  plus de doublons en cliquant sur les boutons "En trouver plus/moins".&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="acces-multiples-a-une-meme-banque"&gt;&lt;a class="toclink" href="#acces-multiples-a-une-meme-banque"&gt;Accès multiples à une même banque&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Kresus ne savait auparavant pas gérer le fait d'avoir plusieurs comptes avec
plusieurs logins / mots de passe dans une même banque (par exemple si vous et
votre compagnon.ne êtes tous les deux dans la même banque). C'est désormais un
problème du passé et réglé dans cette version !&lt;/p&gt;
&lt;h4 id="forcer-la-resynchronisation-du-solde"&gt;&lt;a class="toclink" href="#forcer-la-resynchronisation-du-solde"&gt;Forcer la resynchronisation du solde&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Si vous observez un écart entre le solde sur le site de votre banque et dans
Kresus, et que vous avez essayé toutes les solutions suivantes pour que le
montant affiché dans Kresus corresponde au montant affiché par la banque :
    - Détecter les doublons et les fusionner.
    - Supprimer une opération qui serait dans Kresus mais pas sur le site de
      votre banque.
    - Ajouter manuellement une opération présente sur le site de votre banque
      mais pas dans Kresus.&lt;/p&gt;
&lt;p&gt;Il existe une nouvelle solution (de dernier recours) qui consiste à
resynchroniser purement et simplement le montant donné par Kresus avec celui
indiqué par votre banque.  Dans les paramètres &amp;gt; Comptes bancaires, sur la
ligne du compte à synchroniser, une nouvelle icône (roue crantée) a fait son
apparition ; en cliquant dessus, vous pourrez automatiquement resynchroniser le
solde de votre compte.&lt;/p&gt;
&lt;h4 id="le-point-sysadmin-devops"&gt;&lt;a class="toclink" href="#le-point-sysadmin-devops"&gt;Le point sysadmin / devops&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Si vous avez installé Kresus depuis la version précédente, vous avez
  probablement dû installer Weboob de manière globale sur votre machine. Comme
  c'était une pratique controversée d'un point de vue administration de
  système, il est maintenant possible d'installer Weboob de manière locale (par
  exemple dans un &lt;code&gt;virtualenv&lt;/code&gt;), tout en indiquant à Kresus où se trouve cette
  installation locale, à l'aide de la variable d'environnement
  &lt;code&gt;KRESUS_WEBOOB_DIR&lt;/code&gt; à définir au moment du lancement du serveur :&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$ KRESUS_WEBOOB_DIR=/code/weboob ./bin/kresus&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Merci &lt;a href="https://github.com/nledez"&gt;@nledez&lt;/a&gt; pour cette contribution !&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pour éviter des erreurs lorsque la récupération de vos opérations est trop
  longue (notamment en cas de nombreuses transactions à récupérer), le temps
  d'attente du retour (et traitement) des modules Weboob a été augmenté à 5
  secondes. Pour les utilisateurs de cozy, il vous faudra cependant également
  augmenter le timeout de &lt;code&gt;cozy-proxy&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="maintenance"&gt;&lt;a class="toclink" href="#maintenance"&gt;Maintenance&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Presque chaque version de Kresus arrive avec sa réécriture ; cette fois-ci,
  c'est presque tout le client qui a été réarrangé à l'aide du framework Redux,
  afin d'éviter la duplication d'état et les inconsistances graphiques dans
  l'interface.&lt;/li&gt;
&lt;li&gt;Diverses améliorations ont été apportées afin de faciliter le développement :
  des &lt;a href="http://gph.is/2eH1UlU"&gt;tests unitaires&lt;/a&gt;, des vérifications de cohérence
  au moment de la construction binaire, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="le-mot-de-la-fin"&gt;&lt;a class="toclink" href="#le-mot-de-la-fin"&gt;Le mot de la fin&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Merci à tous les contributeurs, et en particulier aux hyperactifs
&lt;a href="https://nicofrand.eu"&gt;nicofrand&lt;/a&gt; et &lt;a href="https://github.com/ZeHiro"&gt;ZeHiro&lt;/a&gt; pour
avoir participé à l'écriture de ce billet et pour leurs très nombreuses
contributions !&lt;/p&gt;
&lt;p&gt;Comme d'habitude, si vous avez des remarques ou suggestions,
n'hésitez-pas à nous le faire savoir, par
&lt;a href="https://twitter.com/kresusapp"&gt;twitter&lt;/a&gt;, le
&lt;a href="https://kiwiirc.com/client/chat.freenode.net/kresus"&gt;canal IRC&lt;/a&gt;,
la &lt;a href="https://framalistes.org/sympa/info/kresus"&gt;liste de diffusion&lt;/a&gt;,
&lt;a href="https://framasphere.org/people/315a5640ead10132c4cc2a0000053625"&gt;diaspora&lt;/a&gt; ou
encore sur le &lt;a href="https://forum.cozy.io/t/app-kresus/224"&gt;forum&lt;/a&gt; de cozy !&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Mon, 31 Oct 2016 18:30:00 +0100</pubDate><guid isPermaLink="false">tag:bouvier.cc,2016-10-31:/kresus-version-0-9-0/</guid><category>blog</category><category>kresus</category></item><item><title>Laverna Webclipper, the story of a WebExtension</title><link>https://bouvier.cc/laverna-webclipper-webextension/</link><description>&lt;p&gt;Yesterday I've spent my afternoon on a very small side-project related to
&lt;a href="https://laverna.cc/app"&gt;Laverna&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Laverna is an offline-first, no-backend Web application that allows you to
write notes directly from your browser, classify them in notebooks, with a
live-preview Markdown editor and a powerful yet simple tagging system. Besides
being offline-first, it also allows you to sync between different devices,
using &lt;a href="http://dropbox.github.io/dropbox-sdk-js/"&gt;Dropbox&lt;/a&gt; as a backend or your
own instance of a &lt;a href="https://remotestorage.io/"&gt;RemoteStorage&lt;/a&gt; server. All of
this makes it a powerful free and open-source alternative to software like
&lt;a href="http://www.evernote.com/"&gt;Evernote&lt;/a&gt; or even &lt;a href="http://www.onenote.com/"&gt;Microsoft
OneNote&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="a-webclipper-for-laverna"&gt;&lt;a class="toclink" href="#a-webclipper-for-laverna"&gt;A WebClipper for Laverna&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There was already an official
&lt;a href="https://github.com/laverna/webclipper"&gt;webclipper&lt;/a&gt;, but when I've tried it, it
didn't work. Looking at the code and the last commit date, it seemed a bit
deprecated; so I made my own that uses WebExtensions (since I really wanted to
learn a bit more about these), that you can find &lt;a href="https://github.com/bnjbvr/laverna-webclipper"&gt;here on
Github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The idea behind a web clipper is very simple: you go on a Web page that
contains some interesting content and you would like to keep it for later (for
example, to read it later, or to keep it as reference). So the addon
introduces a new click button in the browser bar that opens a new Laverna tab
and prefills the field with the parsed content, one-click away from being
saved. This is useful because some read-it-later services can't have access to
content behind paid-walls, for instance.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bouvier.cc/pub/demo-laverna-webclipper.webm"&gt;See it in action here.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you're interested in getting this addon, you can go on the &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/laverna-clipper/"&gt;official addons
for Firefox
website&lt;/a&gt; (as
of the day of this writing, the addon has not been validated yet).&lt;/p&gt;
&lt;h2 id="the-implementation"&gt;&lt;a class="toclink" href="#the-implementation"&gt;The Implementation&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This project is using &lt;a href="https://github.com/mozilla/readability"&gt;Readability.js&lt;/a&gt;
for retrieving the "interesting content" of a page, and then renders it to
Markdown (since Laverna uses this format) thanks to
&lt;a href="https://github.com/neocotic/html.md"&gt;html.md&lt;/a&gt;. The rest is plumbing :)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://wiki.mozilla.org/WebExtensions"&gt;WebExtensions&lt;/a&gt; are a new safe and
portable way to write addons for Web browsers. Heavily inspired from Chrome's
Addons APIs, the main thrust is that WebExtensions should Just Work© on any Web
browser supporting them (any Chromium-based, Edge and Firefox, as of today).&lt;/p&gt;
&lt;p&gt;This is fantastic news! ... when all the browsers will support it. As of today,
this addon will only work on Firefox, and here is why.&lt;/p&gt;
&lt;p&gt;First, programming a WebExtension is &lt;em&gt;hard&lt;/em&gt;. I mean &lt;strong&gt;really&lt;/strong&gt; hard; debugging
it may quickly become a nightmare, because debug messages can appear in the
developer console (for the content script, which is the "client" part of your
addon), or in a specific addon debugger console (for background scripts), or
even in the &lt;code&gt;stdout&lt;/code&gt; logs of your browser. Some issues, like parsing errors in
your JavaScript files, may be really hard to find in this context.&lt;/p&gt;
&lt;p&gt;Second, at some point in the addon's workflow, you need to inject the Markdown
content into the Laverna's text editor. Laverna uses
&lt;a href="http://codemirror.net/"&gt;CodeMirror&lt;/a&gt; for their rich text editor, so dumping the
content is not just as simple as setting the &lt;code&gt;value&lt;/code&gt; property of the target
&lt;code&gt;textarea&lt;/code&gt;. You need to retrieve the CodeMirror instance somehow and call one of its
methods. The instance is fortunately saved in the
&lt;code&gt;.CodeMirror&lt;/code&gt; property of the textarea, so you could retrieve it, if you really
were on the client page. But browsers don't
&lt;a href="https://developer.chrome.com/extensions/content_scripts#execution-environment"&gt;allow&lt;/a&gt;
&lt;a href="https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts#Xray_vision_in_Firefox"&gt;that&lt;/a&gt;,
unless modifying the observed page itself, which I didn't know about when writing this addon.&lt;/p&gt;
&lt;p&gt;That being said, Firefox gives you a (hacky) way to do so (through
&lt;code&gt;wrappedJSObject&lt;/code&gt;), so you can indeed access the original JS DOM object of the
observed page and retrieve the CodeMirror instance, then call its &lt;code&gt;setValue&lt;/code&gt;
method. Pfew! Chrome doesn't have this hack, which is merely the reason why it
doesn't work there.&lt;/p&gt;
&lt;p&gt;Unrelated to these issues: whenever one clicks on the clipper button, the page
is parsed, which has the unfortunate side-effect of clearing the parsed content
(that's how Readability works). One can clone the entire DOM to prevent this
issue, but this API is not (yet?) available in WebExtensions, at least under
Firefox. To work around this, the page is reloaded in the background after
you've clicked the button. Filthy, right?&lt;/p&gt;
&lt;h2 id="get-in-touch"&gt;&lt;a class="toclink" href="#get-in-touch"&gt;Get in touch!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you have any remarks or suggestions, don't hesitate to ping me on
&lt;a href="https://twitter.com/bnjbvr/"&gt;twitter&lt;/a&gt; or
&lt;a href="https://framasphere.org/people/315a5640ead10132c4cc2a0000053625"&gt;diaspora&lt;/a&gt;; I
love any kind of feedback, since this is usually the only way to get better and
understand what matters. If you're interested in contributing to this addon,
let's get in touch!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Sun, 18 Sep 2016 17:10:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2016-09-18:/laverna-webclipper-webextension/</guid><category>blog</category><category>opensource</category></item><item><title>Une image Docker pour Kresus / Weboob</title><link>https://bouvier.cc/kresus-weboob-docker/</link><description>&lt;p&gt;Si vous suivez ce blog, vous avez dû entendre parler de
&lt;a href="https://framagit.org/bnjbvr/kresus/"&gt;Kresus&lt;/a&gt;, le gestionnaire de finances
personnelles open-source sur lequel je travaille. Pour rappel, cette
application, basée sur &lt;a href="http://weboob.org/"&gt;Weboob&lt;/a&gt;, est disponible dans
&lt;a href="https://cozy.io/en/"&gt;CozyCloud&lt;/a&gt; et vous permet de vous connecter à votre
compte bancaire, récupérer vos opérations et les classifier pour savoir où
votre argent passe.&lt;/p&gt;
&lt;h2 id="kresus-sans-cozy"&gt;&lt;a class="toclink" href="#kresus-sans-cozy"&gt;Kresus sans Cozy&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Depuis quelques versions, vous pouvez également lancer Kresus sans avoir à
installer une instance complète de CozyCloud. Toutes les fonctionnalités ne
sont pas présentes, car soit elles ne sont pas implémentées pour le moment (par
exemple, l'envoi d'alertes par emails), soit elles n'ont pas d'équivalents (par
exemple, les notifications dans le dashboard cozy). Mais tout le reste est là,
et c'est une manière simple et rapide d'utiliser Kresus. Un contributeur,
&lt;a href="https://twitter.com/_nikaro"&gt;Nicolas&lt;/a&gt;, a même écrit un &lt;a href="https://www.karolak.fr/blog/2016/03/18/kresus-un-gestionnaire-web-de-finances-personnelles/"&gt;excellent
tutoriel&lt;/a&gt;
pour ce mode d'installation ! Merci à lui.&lt;/p&gt;
&lt;h2 id="des-precautions"&gt;&lt;a class="toclink" href="#des-precautions"&gt;Des précautions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A savoir : dans la version autonome (ou &lt;em&gt;standalone&lt;/em&gt;) de Kresus, il n'y a
aucune couche d'authentification incluse par défaut, vous devez donc l'ajouter
vous-même pour protéger votre accès à Kresus (sinon tous les gens qui
connaissent l'URL de votre Kresus pourront lire vos comptes !). Aussi, aucune
donnée n'est chiffrée dans la version autonome (pas même le mot de passe), donc
isolez et protégez correctement votre instance.&lt;/p&gt;
&lt;h2 id="nouveau-une-image-docker-pour-kresus-et-weboob"&gt;&lt;a class="toclink" href="#nouveau-une-image-docker-pour-kresus-et-weboob"&gt;Nouveau : une image Docker pour Kresus et Weboob&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;J'ai rajouté récemment, et notablement mis à jour hier soir une &lt;a href="https://framagit.org/bnjbvr/kresus/blob/master/Dockerfile"&gt;image
Docker&lt;/a&gt; qui contient
une version récente de Weboob et lance un Kresus autonome, exposant vers
l'extérieur son port d'écoute (9876 par défaut) et un volume de données. Ce qui
veut dire que vous pouvez maintenant lancer kresus ou weboob en quelques
commandes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;D'abord, récupérer le dépôt :&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git clone https://framagit.org/bnjbvr/kresus &amp;amp;&amp;amp; cd kresus&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Une première fois, créer l'image :&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker build -t kresus .&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Puis ensuite, autant de fois que vous le voulez, vous pouvez instancier
  l'image créée :&lt;/p&gt;
&lt;p&gt;&lt;code&gt;docker run -p 9876:9876 -v /home/moi/kresus-data:/usr/data -ti -d kresus --name kresus&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Si vous désirez exposer Kresus sur le web, pensez bien à suivre le tutoriel
  de Nicolas pour rajouter une couche d'authentification et un serveur web
  proxy.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Suite à ça, vous pouvez ouvrir un navigateur sur &lt;code&gt;http://localhost:9876&lt;/code&gt; et
jouer avec Kresus. Par ailleurs, le répertoire &lt;code&gt;/home/moi/kresus-data&lt;/code&gt;
contiendra les données, dans cet exemple (et vous pouvez donc supprimer
l'image Docker sans perdre vos données). C'est aussi simple que ça !&lt;/p&gt;
&lt;p&gt;Si vous voulez jouer avec les applications de Weboob, il suffit d'ouvrir un
terminal dans le docker qui fait tourner Kresus :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker exec -ti kresus /bin/bash&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Puis dans le bash ouvert : &lt;code&gt;boobank --help&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="des-idees-de-modifications-pour-la-suite"&gt;&lt;a class="toclink" href="#des-idees-de-modifications-pour-la-suite"&gt;Des idées de modifications pour la suite&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Si vous êtes intéressés pour contribuer à Kresus et notamment à cette nouvelle
image Docker, voici quelques idées :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;rajouter un &lt;code&gt;cron&lt;/code&gt; qui mette à jour Weboob régulièrement.&lt;/li&gt;
&lt;li&gt;mettre en place les &lt;em&gt;bonnes pratiques&lt;/em&gt; Docker dans ce Dockerfile.&lt;/li&gt;
&lt;li&gt;mettre en place un serveur frontal &lt;code&gt;nginx&lt;/code&gt; (ou un lien possible) avec un mot
  de passe défini par une variable d'environnement défini au moment de &lt;code&gt;docker
  run&lt;/code&gt; (ou quelque autre solution qui permettrait de rajouter une
  authentification facilement).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="le-mot-de-la-fin"&gt;&lt;a class="toclink" href="#le-mot-de-la-fin"&gt;Le mot de la fin !&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Comme d'habitude, si vous avez des remarques ou suggestions,
n'hésitez-pas à me le faire savoir, sur &lt;a href="https://kiwiirc.com/client/chat.freenode.net/kresus"&gt;irc&lt;/a&gt;, par
&lt;a href="https://twitter.com/bnjbvr/"&gt;twitter&lt;/a&gt;, sur &lt;a href="https://framasphere.org/people/315a5640ead10132c4cc2a0000053625"&gt;diaspora&lt;/a&gt; ou sur le
&lt;a href="https://forum.cozy.io/t/app-kresus/224"&gt;forum&lt;/a&gt; de cozy !&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Mon, 29 Aug 2016 11:30:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2016-08-29:/kresus-weboob-docker/</guid><category>blog</category><category>kresus</category></item><item><title>Kresus: version 0.8.0</title><link>https://bouvier.cc/kresus-version-0-8-0/</link><description>&lt;p&gt;Je viens de publier une nouvelle version de
&lt;a href="https://github.com/bnjbvr/kresus/"&gt;Kresus&lt;/a&gt;, le gestionnaire de finances
personnelles open-source sur lequel je travaille. Pour rappel, cette
application, basée sur &lt;a href="http://weboob.org/"&gt;Weboob&lt;/a&gt;, est disponible dans
&lt;a href="https://cozy.io/en/"&gt;CozyCloud&lt;/a&gt; et vous permet de vous connecter à votre
compte bancaire, récupérer vos opérations et les classifier pour savoir où
votre argent passe.&lt;/p&gt;
&lt;h3 id="action-requise-pour-les-auto-heberges-installation-de-weboob"&gt;&lt;a class="toclink" href="#action-requise-pour-les-auto-heberges-installation-de-weboob"&gt;Action requise pour les auto-hébergés : installation de Weboob&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Avant de passer à la liste détaillée des changements, il y a une procédure de
migration qui nécessitera une action de votre part, si vous êtes auto-hébergés
(c'est-à-dire si vous n'utilisez &lt;strong&gt;pas&lt;/strong&gt; d'instance bêta sur l'infrastructure
de CozyCloud). Si vous êtes utilisateur de l'infrastructure de CozyCloud, le
changement devrait avoir été effectué par l'équipe des administrateurs systèmes
de Cozy, et vous pouvez passer à la partie suivante.&lt;/p&gt;
&lt;p&gt;Si vous êtes auto-hébergés, il vous faudra &lt;a href="http://weboob.org/install"&gt;installer
Weboob&lt;/a&gt; par vos propres moyens et vous assurer que
l'utilisateur qui lance le processus de Kresus ait accès à Weboob. J'ai
personnellement effectué une installation globale. Je &lt;strong&gt;recommande d'installer
la version 1.1 ou supérieure&lt;/strong&gt; de Weboob, pour être certain que les modules des
sites ne soient pas dépassés.&lt;/p&gt;
&lt;p&gt;Si vous utilisez l'application
&lt;a href="https://github.com/cozy/python_cozy_management"&gt;cozy_management&lt;/a&gt;, il existe
maintenant une commande permettant d'effectuer l'installation globale de Weboob
telle qu'elle est nécessaire pour que Kresus fonctionne sur votre machine :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cozy_management install_weboob
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Un grand merci à &lt;a href="https://github.com/nicofrand"&gt;nicofrand&lt;/a&gt; pour cette
fonctionnalité !&lt;/p&gt;
&lt;p&gt;Auparavant, Weboob, le système qui se connecte à votre banque pour récupérer la
liste des comptes et opérations, était installé par Kresus et cela nécessitait
des dépendences externes. Il a été décidé que Weboob devait désormais être
installé au préalable par l'administrateur système : Kresus n'essaiera plus de
l'installer. Cela simplifie beaucoup de choses, notamment en facilitant
la gestion des dépendences nécessaires lors de l'installation.&lt;/p&gt;
&lt;h3 id="la-version-courte"&gt;&lt;a class="toclink" href="#la-version-courte"&gt;La version courte&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Pour cette version, beaucoup de changements peu visibles pour l'utilisateur :
c'est beaucoup de nettoyage et de changements structurels dans le code
(séparation du code client en composants logiques et lint complet), qui
devraient faciliter la maintenance et l'amélioration du code par le futur.
Aussi, beaucoup de problèmes relatifs à la détection des doublons et à la
synchronisation automatique des comptes ont été réglés.&lt;/p&gt;
&lt;p&gt;Un changement visible et notable : la liste des opérations est désormais
&lt;a href="https://twitter.com/bnjbvr/status/730309653943492612"&gt;beaucoup plus fluide&lt;/a&gt;
lors du scroll, même si vous avez des tonnes d'opérations.&lt;/p&gt;
&lt;h3 id="en-cas-de-problemes-de-balances"&gt;&lt;a class="toclink" href="#en-cas-de-problemes-de-balances"&gt;En cas de problèmes de balances&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Si vous rencontrez des problèmes de synchronisation entre Kresus et votre
banque, par exemple si Kresus affiche des soldes de comptes qui ne
correspondent pas aux montants indiqués sur le site de votre banque, il est
conseillé de vérifier les doublons dans la section correspondante et d'essayer
de les fusionner à la main.&lt;/p&gt;
&lt;p&gt;Si malgré la détection de doublons, vous avez encore des problèmes de montant,
laissez un message sur le &lt;a href="https://forum.cozy.io/t/app-kresus/224"&gt;fil associé&lt;/a&gt;
du forum de Cozy ! J'aimerais expérimenter des méthodes plus agressives de
détection automatique de doublons, et cela nécessite de savoir quelles sont les
situations qui posent fréquemment problème.&lt;/p&gt;
&lt;h3 id="les-contributions-en-detail"&gt;&lt;a class="toclink" href="#les-contributions-en-detail"&gt;Les contributions en détail&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Un grand merci aux 7 contributeurs de cette nouvelle version, pour un total de
108 commits !&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/AwYiss"&gt;@AwYiss&lt;/a&gt;, qui avait déjà grandement amélioré
  l'interface utilisateur, a frappé de nouveau, en intégrant les préférences au
  niveau design, rendant cette partie plus consistente avec le reste de
  l'application et très élégante.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nicofrand"&gt;@nicofrand&lt;/a&gt; a corrigé des soucis de style
  (CSS) lors de l'ajout manuel d'opération.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.openhub.net/accounts/Bezleputh"&gt;Bezleputh&lt;/a&gt; (de la communauté
  Weboob) a corrigé un bogue qui empêchait l'import d'opérations, si celles-ci
  présentaient des informations manquantes.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/brouberol"&gt;@brouberol&lt;/a&gt; a ajouté un Dockerfile (ou
  &lt;a href="https://github.com/brouberol/marcel"&gt;RecetteÀMarcel&lt;/a&gt; pour les puristes de l'OS
  souverain) afin de pouvoir tester Kresus rapidement en production. J'espère
  pouvoir écrire un peu plus sur le sujet bientôt.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/PandiPanda69"&gt;@PandiPanda69&lt;/a&gt; a effectué une revue du code
  avec la sécurité à l'esprit :&lt;ul&gt;
&lt;li&gt;Correction de bogue : lors de l'import d'une instance, si le fichier JSON
  contient des erreurs de syntaxe, ne pas essayer de l'importer.&lt;/li&gt;
&lt;li&gt;Ajout de la possibilité de chiffrer l'export de son instance Kresus et
  d'importer une instance chiffrée de Kresus. Avec cette nouvelle méthode
  d'import, le mot de passe peut être inclus dans le fichier exporté, en
  toute sécurité ! (cette fonctionnalité n'est pas encore activée car elle
  nécessite une réflexion et des tests approfondis ainsi qu'une
  implémentation côté interface)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ZeHiro"&gt;@ZeHiro&lt;/a&gt;:&lt;ul&gt;
&lt;li&gt;Amélioration de la visualisation de la liste des opérations sur interface
  mobile (en lecture seule pour le moment).&lt;/li&gt;
&lt;li&gt;Amélioration sensible des traductions : les notifications et textes des
  emails sont désormais traduits en français ou en anglais, selon la langue
  choisie dans votre Cozy !&lt;/li&gt;
&lt;li&gt;Utilisation de la vraie monnaie du compte, avec le symbole monétaire
  associé, dans toute l'interface utilisateur.&lt;/li&gt;
&lt;li&gt;Amélioration de la détection manuelle des doublons (deux opérations sont
  considérées comme des doublons seulement si leurs types sont identiques).&lt;/li&gt;
&lt;li&gt;Suppression de faux positifs dans la détection automatique des doublons
  (deux opérations avec la même date, le même montant et le même libellé).&lt;/li&gt;
&lt;li&gt;Si votre mot de passe expire, Kresus vous enverra désormais un mail une
  et une seule fois pour vous le signaler, et n'importera plus d'opérations
  automatiquement jusqu'à la mise à jour du mot de passe (le même comportement
  est prévu si le mot de passe devient erroné, s'il n'est pas mis à jour dans
  Kresus).&lt;/li&gt;
&lt;li&gt;Ajout de la possibilité de supprimer une opération manuellement.
  N'utilisez cette fonctionnalité qu'en dernier recours et seulement si la
  détection de doublons n'a pas marché !&lt;/li&gt;
&lt;li&gt;Fix spécifique à un &lt;a href="https://framagit.org/bnjbvr/kresus/issues/401"&gt;problème
  spécifique&lt;/a&gt; de plateforme
  sous raspberry pi.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;De manière notable, ZeHiro et moi-même avons contribué ensemble à des
  fonctionnalités majeures :&lt;ul&gt;
&lt;li&gt;Grâce à une implémentation de &lt;em&gt;l'infinite scrolling&lt;/em&gt; dans la
  liste des opérations, celle-ci est bien plus fluide à s'afficher, même si
  vous avez beaucoup d'opérations !&lt;/li&gt;
&lt;li&gt;Découpage du code en modules logiques et refactoring pour que le code
  client passe le lint (validation statique du style du code). Ce n'est pas
  visible pour l'utilisateur, mais ça aide grandement les développeurs en
  leur évitant de se poser plein de questions futiles sur le style du code.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bnjbvr"&gt;votre serviteur&lt;/a&gt;:&lt;ul&gt;
&lt;li&gt;utilisation de Weboob au niveau global (voir paragraphe sur la procédure
  de migration).&lt;/li&gt;
&lt;li&gt;meilleure représentation des erreurs. Normalement, les erreurs devraient
  être plus claires à comprendre, côté client comme ou dans les logs côté
  serveur, grâce à une meilleure cohérence et à des logs plus détaillés et
  facultatifs. Un mode de debugging pour Weboob a été également rajouté, ce
  qui est très utile en cas de problèmes de synchronisation avec votre
  banque, pour remonter des logs aux développeurs de Weboob !&lt;/li&gt;
&lt;li&gt;la récupération automatique des opérations ne s'arrête plus en cas
  d'échec. Si les opérations n'étaient plus récupérées automatiquement
  toutes les nuits chez vous, c'était peut-être à cause de ce bug.&lt;/li&gt;
&lt;li&gt;les graphiques des opérations en valeurs négatives pointent désormais
  vers le haut et non plus vers le bas.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="le-mot-de-la-fin"&gt;&lt;a class="toclink" href="#le-mot-de-la-fin"&gt;Le mot de la fin&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;La prochaine version est déjà presque prête et comprend une réécriture presque
complète du client avec une autre technologie (&lt;code&gt;redux&lt;/code&gt;). Après cette
réécriture, on devrait plus facilement pouvoir ajouter de nouveau des grosses
fonctionnalités !&lt;/p&gt;
&lt;p&gt;Comme d'habitude, si vous avez des remarques ou suggestions,
n'hésitez-pas à me le faire savoir, par
&lt;a href="https://twitter.com/bnjbvr/"&gt;twitter&lt;/a&gt;, sur &lt;a href="https://framasphere.org/people/315a5640ead10132c4cc2a0000053625"&gt;diaspora&lt;/a&gt; ou sur le
&lt;a href="https://forum.cozy.io/t/app-kresus/224"&gt;forum&lt;/a&gt; de cozy !&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Fri, 05 Aug 2016 19:30:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2016-08-05:/kresus-version-0-8-0/</guid><category>blog</category><category>kresus</category></item><item><title>Making asm.js/WebAssembly compilation more parallel in Firefox</title><link>https://bouvier.cc/making-asmjs-webassembly-compilation-more-parallel/</link><description>&lt;p&gt;In December 2015, I've worked on reducing startup time of asm.js programs in
Firefox by making compilation more parallel. As our
JavaScript engine, Spidermonkey, uses the same compilation pipeline for both
asm.js and WebAssembly, this also benefitted WebAssembly compilation. Now is a
good time to talk about what it meant, how it got achieved and what are the
next ideas to make it even faster.&lt;/p&gt;
&lt;h1 id="what-does-it-mean-to-make-a-program-more-parallel"&gt;&lt;a class="toclink" href="#what-does-it-mean-to-make-a-program-more-parallel"&gt;What does it mean to make a program "more parallel"?&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Parallelization consists of splitting a sequential program into smaller
independent tasks, then having them run on different CPU. If your program
is using &lt;code&gt;N&lt;/code&gt; cores, it can be up to &lt;code&gt;N&lt;/code&gt; times faster.&lt;/p&gt;
&lt;p&gt;Well, in theory. Let's say you're in a car, driving on a 100 Km long road.
You've already driven the first 50 Km in one hour. Let's say your car can
have unlimited speed from now on. What is the maximal average speed you can
reach, once you get to the end of the road?&lt;/p&gt;
&lt;p&gt;People intuitively answer "If it can go as fast as I want, so nearby lightspeed
sounds plausible". But this is not true! In fact, if you could teleport from
your current position to the end of the road, you'd have traveled 100 Km in one
hour, so your maximal theoritical speed is 100 Km per hour. This result is a
consequence of &lt;a href="https://en.wikipedia.org/wiki/Amdahl%27s_law"&gt;Amdahl's law&lt;/a&gt;.
When we get back to our initial problem, this means you can expect a &lt;code&gt;N&lt;/code&gt; times
speedup if you're running your program with &lt;code&gt;N&lt;/code&gt; cores if, and only if your
program can be &lt;strong&gt;entirely&lt;/strong&gt; run in parallel. This is usually not the case, and
that is why most wording refers to &lt;em&gt;speedups &lt;/em&gt;&lt;em&gt;up to&lt;/em&gt;&lt;em&gt; N times faster&lt;/em&gt;, when it
comes to parallelization.&lt;/p&gt;
&lt;p&gt;Now, say your program is already running some portions in parallel. To make it
faster, one can identify some parts of the program that are sequential, and make
them independent so that you can run them in parallel. With respect to our car
metaphor, this means augmenting the portion of the road on which you can run at
unlimited speed.&lt;/p&gt;
&lt;p&gt;This is exactly what we have done with parallel compilation of asm.js programs
under Firefox.&lt;/p&gt;
&lt;h1 id="a-quick-look-at-the-asmjs-compilation-pipeline"&gt;&lt;a class="toclink" href="#a-quick-look-at-the-asmjs-compilation-pipeline"&gt;A quick look at the asm.js compilation pipeline&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;I recommend to read this &lt;a href="https://blog.mozilla.org/luke/2014/01/14/asm-js-aot-compilation-and-startup-performance/"&gt;blog
post&lt;/a&gt;.
It clearly explains the differences between JIT (Just In Time) and AOT (Ahead
Of Time) compilation, and elaborates on the different parts of the engines
involved in the compilation pipeline.&lt;/p&gt;
&lt;p&gt;As a TL;DR, keep in mind that &lt;a href="http://asmjs.org/"&gt;asm.js&lt;/a&gt; is a strictly
validated, highly optimizable, typed subset of JavaScript. Once
validated, it guarantees high performance and stability (no garbage collector
involved!). That is ensured by
mapping every single JavaScript instruction of this subset to a few CPU
instructions, if not only a single instruction. This means an asm.js program
needs to get &lt;em&gt;compiled&lt;/em&gt; to machine code, that is, translated from JavaScript to
the language your CPU directly manipulates (like what GCC would do for a C++
program). If you haven't heard, the results are impressive and you can run
&lt;a href="beta.unity3d.com/jonas/DT2/"&gt;video&lt;/a&gt;
&lt;a href="https://www.unrealengine.com/html5"&gt;games&lt;/a&gt; directly in your browser, without
needing to install anything. No plugins. Nothing more than your usual, everyday
browser.&lt;/p&gt;
&lt;p&gt;Because asm.js programs can be gigantic in size (in number of functions as well
as in number of lines of code), the first compilation of the entire program is
going to take some time. Afterwards, Firefox uses a caching mechanism that
prevents the need for recompilation and almost instaneously loads the code, so
subsequent loadings matter less&lt;strong&gt;*&lt;/strong&gt;. The end user will mostly wait for the
first compilation, thus this one needs to be fast.&lt;/p&gt;
&lt;p&gt;Before the work explained below, the pipeline for compiling a single function
(out of an asm.js module) would look like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;parse the function, and as we parse, emit intermediate representation (IR)
  nodes for the compiler infrastructure. SpiderMonkey has several IRs,
  including the MIR (middle-level IR, mostly loaded with semantic) and the LIR
  (low-level IR closer to the CPU memory representation: registers, stack,
  etc.). The one generated here is the MIR. All of this happens on the main
  thread.&lt;/li&gt;
&lt;li&gt;once the entire IR graph is generated for the function, optimize the MIR
  graph (i.e. apply a few optimization passes). Then, generate the LIR graph
  before carrying out register allocation (probably the most costly task of the
  pipeline). This can be done on supplementary helper threads, as the MIR
  optimization and LIR generation for a given function doesn't depend on other
  ones.&lt;/li&gt;
&lt;li&gt;since functions can call between themselves within an asm.js module, they
  need references to each other. In assembly, a reference is merely an offset
  to somewhere else in memory. In this initial implementation, code generation
  is carried out on the main thread, at the cost of speed but for the sake of
  simplicity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So far, only the MIR optimization passes, register allocation and LIR
generation were done in parallel. Wouldn't it be nice to be able to do more?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;*&lt;/strong&gt; There are conditions for benefitting from the caching mechanism. In
particular, the script should be loaded
&lt;a href="https://developer.mozilla.org/en-US/docs/Games/Techniques/Async_scripts"&gt;asynchronously&lt;/a&gt;
and it should be of a consequent size.&lt;/p&gt;
&lt;h1 id="doing-more-in-parallel"&gt;&lt;a class="toclink" href="#doing-more-in-parallel"&gt;Doing more in parallel&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Our goal is to make more work in parallel: so can we take out MIR generation
from the main thread? And we can take out code generation as well?&lt;/p&gt;
&lt;p&gt;The answer happens to be &lt;em&gt;yes&lt;/em&gt; to both questions.&lt;/p&gt;
&lt;p&gt;For the former, instead of emitting a MIR graph as we parse the function's
body, we emit a small, compact, pre-order representation of the function's
body. In short, a new IR. As work was starting on
&lt;a href="https://github.com/webassembly/design"&gt;WebAssembly&lt;/a&gt; (wasm) at this time, and
since asm.js semantics and wasm semantics mostly match, the IR could just be
the wasm
&lt;a href="https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md"&gt;encoding&lt;/a&gt;,
consisting of the wasm opcodes plus a few specific asm.js ones*. Then, wasm
is translated to MIR in another thread.&lt;/p&gt;
&lt;p&gt;Now, instead of parsing and generating MIR in a single pass, we would now parse
and generate wasm IR in one pass, and generate the MIR out of the wasm IR in
another pass. The wasm IR is very compact and much cheaper to generate than a
full MIR graph, because generating a MIR graph needs some algorithmic work,
including the creation of Phi nodes (join values after any form of branching).
As a result, it is expected that compilation time won't suffer.  This was a
large refactoring: taking every single asm.js instructions, and encoding them
in a compact way and later decode these into the equivalent MIR nodes.&lt;/p&gt;
&lt;p&gt;For the second part, could we generate code on other threads? One structure in
the code base, the &lt;em&gt;MacroAssembler&lt;/em&gt;, is used to generate all the code and it
contains all necessary metadata about offsets. By adding more metadata there to
abstract internal calls &lt;strong&gt;**&lt;/strong&gt;, we can describe the new scheme in terms of a
classic functional &lt;code&gt;map&lt;/code&gt;/&lt;code&gt;reduce&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the wasm IR is sent to a thread, which will return a MacroAssembler. That
  is a &lt;code&gt;map&lt;/code&gt; operation, transforming an array of wasm IR into an array of
  MacroAssemblers.&lt;/li&gt;
&lt;li&gt;When a thread is done compiling, we merge its MacroAssembler into one big
  MacroAssembler. Most of the merge consists in taking all the offset metadata
  in the thread MacroAssembler, fixing up all the offsets, and concatenate the
  two generated code buffers. This is equivalent to a &lt;code&gt;reduce&lt;/code&gt; operation,
  merging each MacroAssembler within the module's one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the end of the compilation of the entire module, there is still some light
work to be done: offsets of internal calls need to be translated to their
actual locations. All this work has been done in &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1181612"&gt;this bugzilla
bug&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;*&lt;/strong&gt; In fact, at the time when this was being done, we used a different
superset of wasm. Since then, work has been done so that our asm.js frontend is
really just another wasm emitter.&lt;/p&gt;
&lt;p&gt;**** ** referencing functions by their appearance order index in the module,
rather than an offset to the actual start of the function. This order is indeed
stable, from a function to the other.&lt;/p&gt;
&lt;h1 id="results"&gt;&lt;a class="toclink" href="#results"&gt;Results&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Benchmarking has been done on a Linux x64 machine with 8 cores clocked at 4.2
Ghz.&lt;/p&gt;
&lt;p&gt;First, compilation times of a few asm.js massive games:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://beta.unity3d.com/jonas/DT2/"&gt;DeadTrigger2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://beta.unity3d.com/jonas/AngryBots/"&gt;AngryBots&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lukewagner/PlatformerGamePacked"&gt;Platformer game&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.unrealengine.com/html5"&gt;Tappy Chicken&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The X scale is the compilation time in seconds, so lower is better. Each value
point is the best one of three runs. For the new scheme, the corresponding
relative speedup (in percentage) has been added:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Compilation times of various
benchmarks" src="https://bouvier.cc/img/2016-04-22_parallelization-times.png"&gt;&lt;/p&gt;
&lt;p&gt;For all games, compilation is much faster with the new parallelization scheme.&lt;/p&gt;
&lt;p&gt;Now, let's go a bit deeper. The Linux CLI tool &lt;code&gt;perf&lt;/code&gt; has a &lt;code&gt;stat&lt;/code&gt; command
that gives you an average of the number of utilized CPUs during the program
execution. This is a great measure of threading efficiency: the more a CPU is
utilized, the more it is not idle, waiting for other results to come, and thus
useful. For a constant task execution time, the more utilized CPUs, the more
likely the program will execute quickly.&lt;/p&gt;
&lt;p&gt;The X scale is the number of utilized CPUs, according to the &lt;code&gt;perf stat&lt;/code&gt;
command, so higher is better. Again, each value point is the best one of three
runs.&lt;/p&gt;
&lt;p&gt;&lt;img alt="CPU utilized on DeadTrigger2" src="https://bouvier.cc/img/2016-04-22_parallelization-cpu-utilized.png"&gt;&lt;/p&gt;
&lt;p&gt;With the older scheme, the number of utilized CPUs quickly rises up from 1 to 4
cores, then more slowly from 5 cores and beyond. Intuitively, this means that
with 8 cores, we almost reached the theoritical limit of the portion of the
program that can be made parallel (not considering the overhead introduced by
parallelization or altering the scheme).&lt;/p&gt;
&lt;p&gt;But with the newer scheme, we get much more CPU usage even after 6 cores! Then
it slows down a bit, although it is still more significant than the slow rise
of the older scheme. So it is likely that with even more threads, we could have
even better speedups than the one mentioned beforehand. In fact, we have moved
the theoritical limit mentioned above a bit further: we have expanded the
portion of the program that can be made parallel. Or to keep on using the
initial car/road metaphor, we've shortened the constant speed portion of the
road to the benefit of the unlimited speed portion of the road, resulting in a
shorter trip overall.&lt;/p&gt;
&lt;h1 id="future-steps"&gt;&lt;a class="toclink" href="#future-steps"&gt;Future steps&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Despite these improvements, compilation time can still be a pain, especially on
mobile. This is mostly due to the fact that we're running a whole multi-million
line codebase through the backend of a compiler to generate optimized code.
Following this work, the next bottleneck during the compilation process is
parsing, which matters for asm.js in particular, which source is plain text.
Decoding WebAssembly is an order of magnitude faster though, and it can be made
even faster. Moreover, we have even more load-time optimizations coming down
the pipeline!&lt;/p&gt;
&lt;p&gt;In the meanwhile, we keep on improving the WebAssembly backend. Keep track of
our progress on &lt;a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188259"&gt;bug
1188259&lt;/a&gt;!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Fri, 22 Apr 2016 15:00:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2016-04-22:/making-asmjs-webassembly-compilation-more-parallel/</guid><category>blog</category><category>compilers</category><category>opensource</category><category>mozilla</category></item><item><title>Previous writings about Mozilla work</title><link>https://bouvier.cc/previous-writing-about-mozilla-work/</link><description>&lt;p&gt;I am currently a compiler engineer at Mozilla corporation, the company making
the Firefox browser among else. Our JavaScript virtual machine, Spidermonkey,
is split in several tiers, including an highly optimizing Just-In-Time (JIT)
compiler able to compile JavaScript to assembly at runtime. My previous work
has involved efficiently compiling Float32 arithmetic to hardware instructions
and implement a new SIMD API for the Web.&lt;/p&gt;
&lt;h2 id="about-float32-optimizations"&gt;&lt;a class="toclink" href="#about-float32-optimizations"&gt;About Float32 optimizations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The full blog post is
&lt;a href="https://blog.mozilla.org/javascript/2013/11/07/efficient-float32-arithmetic-in-javascript/"&gt;there&lt;/a&gt;.
It has been written in November 2013.&lt;/p&gt;
&lt;p&gt;The main idea is that if you have float32 inputs to an operation; and you cast
them to doubles; and you apply an arithmetic operation to these inputs; and you
cast the result back to a float32, then you'd have the same result as if you
did the entire computation with float32 values and operations.&lt;/p&gt;
&lt;p&gt;So we've introduced an operation in JavaScript that converts a Number to its
closest float32 IEEE754 representation: &lt;code&gt;Math.fround&lt;/code&gt;. Said differently, the
above equivalence says that:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;xf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fround&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;yf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fround&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fround&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;xf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;yf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// For all x, y that can be represented exactly as float32:&lt;/span&gt;
&lt;span class="nx"&gt;assert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Yes, &lt;code&gt;===&lt;/code&gt;. The same &lt;code&gt;===&lt;/code&gt; you've been told &lt;strong&gt;not&lt;/strong&gt; to use for floating-point
Numbers. But here, we have &lt;em&gt;bitwise&lt;/em&gt; equality, so we can use strict equality*.&lt;/p&gt;
&lt;p&gt;Processors have special instructions for carrying out float32 arithmetic, which
have higher throughput than the equivalent double ones. With this result in
mind, we could add a pass that would spot opportunities where the computations
are equivalent (thanks to &lt;code&gt;Math.fround&lt;/code&gt; hints) and emit float32 instructions
instead of double instructions. This sped up a some numerical applications and
games engines by a few points.&lt;/p&gt;
&lt;p&gt;* a careful reader would object that this is wrong for &lt;code&gt;x = y = NaN&lt;/code&gt;, which
I've put away for the sake of simplicity.&lt;/p&gt;
&lt;h2 id="about-simdjs"&gt;&lt;a class="toclink" href="#about-simdjs"&gt;About SIMD.js&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The full blog post is
&lt;a href="https://blog.mozilla.org/javascript/2015/03/10/state-of-simd-js-performance-in-firefox/"&gt;there&lt;/a&gt;.
It has been written in March 2015.&lt;/p&gt;
&lt;p&gt;Nowadays, processors have instructions sets that allow them to execute several
simple arithmetic operations at once. For instance, let's say you have two
arrays of integers and you want to add each element to the corresponding one in
the other array. If both arrays have size &lt;code&gt;N&lt;/code&gt;, this means you'll have to carry
out &lt;code&gt;N&lt;/code&gt; scalar additions. But processors can actually group these into bundles
of several additions, with SIMD; for the case of 32-bits wide integers, on most
modern processors, you need at most &lt;code&gt;Math.ceil(N / 4)&lt;/code&gt; instructions. The blog
post details what SIMD.js is and what bottlenecks we hit during implementation.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This was a small reminder about previously written blog posts. If you're into
JavaScript, compilers or low-level optimization, I can only recommend you to go
read the &lt;a href="https://blog.mozilla.org/javascript/"&gt;Mozilla's JavaScript blog&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Wed, 09 Mar 2016 18:00:00 +0100</pubDate><guid isPermaLink="false">tag:bouvier.cc,2016-03-09:/previous-writing-about-mozilla-work/</guid><category>blog</category><category>compilers</category><category>opensource</category><category>mozilla</category></item><item><title>A Tale Of Linux On The Desktop</title><link>https://bouvier.cc/installing-linux/</link><description>&lt;p&gt;So I've received a new desktop machine at home, on which only
Windows 10 was installed. I've decided to install Linux, for my day-to-day
hacking.  Unfortunately, when I've plugged the Ubuntu (nobody's perfect) USB
drive to my computer, I had the surprise to see a black screen showing up just
after booting, and nothing else. Here are some notes taken during the
installation of Linux on this machine.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Twitter fame" src="https://bouvier.cc/img/2016-01-27_installing-linux-twitter.png"&gt;&lt;/p&gt;
&lt;h2 id="graphics-not-working"&gt;&lt;a class="toclink" href="#graphics-not-working"&gt;Graphics not working&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Graphics don't work, but we can still install Ubuntu in non-graphic mode
with an &lt;a href="http://www.ubuntu.com/download/alternative-downloads"&gt;alternate install
image&lt;/a&gt;, namely the
network installer. Let's try that.&lt;/p&gt;
&lt;p&gt;The machine has a Nvidia graphics card, so the open-source Nouveau graphics
driver is used by default. Suspecting proprietary drivers might solve the
problem, I decide to download them. Then, to my greatest surprise, I find out
network isn't working, be it the wireless network or Ye Olde Ethernet network.&lt;/p&gt;
&lt;h2 id="ethernet-not-working"&gt;&lt;a class="toclink" href="#ethernet-not-working"&gt;Ethernet not working&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The computer vendor's website says the network card is an Atheros Killer 2400.
Looking that up on the web with my favorite &lt;a href="https://duckduckgo.com"&gt;search
engine&lt;/a&gt;, this &lt;a href="http://askubuntu.com/questions/670347/is-there-any-way-to-install-atheros-e2400-drivers"&gt;StackOverflow
page&lt;/a&gt;
showed up. The solution to make ethernet work at the end of the installation is
the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;modprobe alx
echo 1969 e0a1 &amp;gt; /sys/bus/pci/drivers/alx/new_id
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This enables the module &lt;code&gt;alx&lt;/code&gt; and registers the device to the module. Now
ethernet is working. Fiuu. Let's keep moving.&lt;/p&gt;
&lt;h2 id="install-all-the-drivers"&gt;&lt;a class="toclink" href="#install-all-the-drivers"&gt;Install All The Drivers!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://help.ubuntu.com/community/BinaryDriverHowto/Nvidia"&gt;ubuntu's nvidia troubleshooting
page&lt;/a&gt; gives you a
nice tool that show you what drivers are adapted to your hardware:
&lt;code&gt;ubuntu-drivers&lt;/code&gt;. Here's an output example given by this command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;ubuntu-drivers&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;devices&lt;/span&gt;
&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;
vendor&lt;span class="w"&gt;   &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;NVIDIA&lt;span class="w"&gt; &lt;/span&gt;Corporation
modalias&lt;span class="w"&gt; &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;pci:v000010DEd00000FE9sv0000106Bsd00000130bc03sc00i00
driver&lt;span class="w"&gt;   &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;xserver-xorg-video-nouveau&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;distro&lt;span class="w"&gt; &lt;/span&gt;free&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;builtin&lt;/span&gt;
driver&lt;span class="w"&gt;   &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;nvidia-340-updates&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;distro&lt;span class="w"&gt; &lt;/span&gt;non-free
driver&lt;span class="w"&gt;   &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;nvidia-340&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;distro&lt;span class="w"&gt; &lt;/span&gt;non-free
driver&lt;span class="w"&gt;   &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;nvidia-352&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;distro&lt;span class="w"&gt; &lt;/span&gt;non-free&lt;span class="w"&gt; &lt;/span&gt;recommended
driver&lt;span class="w"&gt;   &lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;nvidia-352-updates&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;distro&lt;span class="w"&gt; &lt;/span&gt;non-free
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So this tells me what the recommanded driver for my nvidia card is. For bonus
credit, it also shows me a recommended driver for the builtin WiFi card. Once
I've installed it, it has been working like a charm!&lt;/p&gt;
&lt;h2 id="moar-graphics-settings"&gt;&lt;a class="toclink" href="#moar-graphics-settings"&gt;Moar graphics settings&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After the nvidia driver has been installed, a
&lt;a href="https://help.ubuntu.com/community/BinaryDriverHowto/Nvidia#Screen_Blanks.2FMonitor_Turns_Off"&gt;tweak&lt;/a&gt;
was needed to ensure the driver outputs video on the DVI port instead of the
VGA port. Beforehand, the &lt;code&gt;xorg.conf&lt;/code&gt; file was generated thanks to the
&lt;code&gt;nvidia-xsettings&lt;/code&gt; command.&lt;/p&gt;
&lt;h2 id="final-boss-uefi"&gt;&lt;a class="toclink" href="#final-boss-uefi"&gt;Final boss: UEFI&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that all minimal drivers are correctly installed and configured, let's try
to reboot. Although I've installed the grub bootloader on the main disk, I
can't find a way to access it, even by trying all the lines in the boot menu.&lt;/p&gt;
&lt;p&gt;The reason is that I've boot up the USB drive in legacy mode, which is not UEFI
mode. As a matter of fact, Ubuntu has been installed in legacy mode but the
machine is booting with UEFI, so Linux can't be seen from the bootloader.&lt;/p&gt;
&lt;p&gt;Fortunately, this is Linux, and everything that has been done can be undone. If
you can find a way to boot with UEFI &lt;strong&gt;and&lt;/strong&gt; log in under Linux (maybe
&lt;a href="https://help.ubuntu.com/community/BasicChroot"&gt;chrooting&lt;/a&gt;), then you can
follow &lt;a href="https://help.ubuntu.com/community/UEFI#Converting_Ubuntu_into_UEFI_mode"&gt;this
procedure&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I couldn't boot in UEFI mode, but I could run the
&lt;a href="http://sourceforge.net/p/boot-repair-cd/home/Home/"&gt;Boot-Repair-Disk&lt;/a&gt; on USB
as UEFI, so I've followed the procedure there and converted my installation
into UEFI mode.&lt;/p&gt;
&lt;h2 id="linux-after-all"&gt;&lt;a class="toclink" href="#linux-after-all"&gt;Linux After All&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;And here we are, with Linux working out of the box^W^W^W^W. So yes, 2016 will
be another year of Linux on the desktop for me; but it still feels unlikely for
a newcomer to install Ubuntu and see it Just Work on any given machine, so
maybe 2017 will be the year of Linux on the desktop, but not 2016.&lt;/p&gt;
&lt;p&gt;Many thanks to &lt;a href="https://twitter.com/etnbrd"&gt;@etnbrd&lt;/a&gt;,
&lt;a href="https://twitter.com/martiusweb/"&gt;@martiusweb&lt;/a&gt; and
&lt;a href="https://twitter.com/padenot"&gt;@padenot&lt;/a&gt; for the detailed explanations about
some Linux specifics and for advices.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Wed, 27 Jan 2016 21:00:00 +0100</pubDate><guid isPermaLink="false">tag:bouvier.cc,2016-01-27:/installing-linux/</guid><category>blog</category><category>opensource</category></item><item><title>Kresus: version 0.7.0</title><link>https://bouvier.cc/kresus-version-0-7-0/</link><description>&lt;p&gt;Je viens de publier une nouvelle version de
&lt;a href="https://github.com/bnjbvr/kresus/"&gt;Kresus&lt;/a&gt;, le gestionnaire de finances
personnelles open-source sur lequel je travaille. Pour rappel, cette
application, basée sur &lt;a href="http://weboob.org/"&gt;Weboob&lt;/a&gt;, est disponible dans
&lt;a href="https://cozy.io/en/"&gt;CozyCloud&lt;/a&gt; et vous permet de vous connecter à votre
compte bancaire, récupérer vos opérations et les classifier pour savoir où
votre argent passe.&lt;/p&gt;
&lt;h3 id="la-version-courte"&gt;&lt;a class="toclink" href="#la-version-courte"&gt;La version courte&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Coup de pinceau magistral sur l'interface, merci @AwYiss !&lt;/li&gt;
&lt;li&gt;Support de nouvelles banques, merci @ZeHiro !&lt;/li&gt;
&lt;li&gt;Possibilité de sélectionner un compte par défaut, merci @nicofrand !&lt;/li&gt;
&lt;li&gt;Réparation du lien entre factures et opérations bancaires, merci @ZeHiro !&lt;/li&gt;
&lt;li&gt;Couleurs associées aux catégories, merci @nicofrand !&lt;/li&gt;
&lt;li&gt;Réparation du module HelloBank.&lt;/li&gt;
&lt;li&gt;Mise à jour automatique quotidienne de Weboob.&lt;/li&gt;
&lt;li&gt;L'installation sera désormais plus rapide (l'application est précompilée par
  les développeurs, et non plus compilée au moment de l'installation).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="les-contributions-en-detail"&gt;&lt;a class="toclink" href="#les-contributions-en-detail"&gt;Les contributions en détail&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Un grand merci à tous les contributeurs qui ont été hyperactifs ce mois-ci !&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/AwYiss"&gt;@AwYiss&lt;/a&gt; a personnalisé et donné un coup de jeune
  à toute l'interface ! Notamment, l'interface est maintenant utilisable sur
  mobile. Merci @AwYiss!&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nicofrand"&gt;@nicofrand&lt;/a&gt; a été prolifique :&lt;ul&gt;
&lt;li&gt;Il y a désormais un bouton "fermer" et un bouton "vider et fermer" dans
  la fenêtre de recherche des opérations, qui explicitent mieux les
  intentions.&lt;/li&gt;
&lt;li&gt;Il est maintenant possible d'éditer les champs personnalisés de connexion
  aux banques (par ex. la phrase secrète de connexion, etc.).&lt;/li&gt;
&lt;li&gt;Un compte peut désormais être sélectionné comme compte par défaut, dans
  les préférences (étoile à côté des comptes). C'est ce compte-là qui
  s'affichera en premier quand vous vous connecterez à Kresus.&lt;/li&gt;
&lt;li&gt;Kresus a une belle favicon, pour les versions mobiles !&lt;/li&gt;
&lt;li&gt;Weboob peut être mis à jour sans qu'aucun compte ne soit présent, grâce à
  l'onglet "avancé" affiché lors de l'installation.&lt;/li&gt;
&lt;li&gt;Il est désormais possible d'assigner une couleur à une catégorie. Cette
  couleur sera utilisée dans les graphiques en barre et en camembert pour
  représenter ladite catégorie.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/ZeHiro"&gt;@ZeHiro&lt;/a&gt; a également été très efficace :&lt;ul&gt;
&lt;li&gt;Il est désormais possible de retirer un libellé personalisé d'une
  opération.&lt;/li&gt;
&lt;li&gt;Il est possible de quitter le champ de libellé personalisé en pressant
  Echap.&lt;/li&gt;
&lt;li&gt;Les factures liées par Konnector n'étaient pas récupérées correctement,
  c'est maintenant réparé !&lt;/li&gt;
&lt;li&gt;Support de quelques nouvelles banques et intégration de toutes les
  variantes des banques, avec les icônes associées !&lt;/li&gt;
&lt;li&gt;Des opérations peuvent être rajoutées à la main dans un compte. Bien que
  cela soit très utile, c'est pour le moment mal géré par la reconnaissance
  automatique des opérations, et donc à n'utiliser que si vous savez
  vraiment bien ce que vous faites.&lt;/li&gt;
&lt;li&gt;Qualité du code : début de lint côté client.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bnjbvr"&gt;votre serviteur&lt;/a&gt; :&lt;ul&gt;
&lt;li&gt;mise à jour du module bancaire HelloBank&lt;/li&gt;
&lt;li&gt;fusion automatique des comptes doublons très probables&lt;/li&gt;
&lt;li&gt;mise à jour automatique des modules weboob, une fois par jour&lt;/li&gt;
&lt;li&gt;possibilité de changer le login d'accès à une banque&lt;/li&gt;
&lt;li&gt;amélioration de la qualité du code avec un lint côté serveur&lt;/li&gt;
&lt;li&gt;meilleur affichage des erreurs côté client&lt;/li&gt;
&lt;li&gt;mise à jour du système de build, des fichiers lisez-moi, etc.&lt;/li&gt;
&lt;li&gt;simplification des traductions et ajout d'un script pour vérifier la
  cohérence entre les traductions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Si vous voulez voir encore plus de détails, les commits sont présentés &lt;a href="https://github.com/bnjbvr/kresus/compare/2c502f6c32fc6c51b60eae17fd53453343c8e305...f42832a23826ad3f003e84840ae5af59885304a9"&gt;par
là&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id="le-mot-de-la-fin"&gt;&lt;a class="toclink" href="#le-mot-de-la-fin"&gt;Le mot de la fin&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Comme d'habitude, si vous avez des remarques ou suggestions,
n'hésitez-pas à me le faire savoir, par
&lt;a href="https://twitter.com/bnjbvr/"&gt;twitter&lt;/a&gt; ou sur le
&lt;a href="https://forum.cozy.io/t/app-kresus/224"&gt;forum&lt;/a&gt; de cozy !&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Mon, 18 Jan 2016 23:59:00 +0100</pubDate><guid isPermaLink="false">tag:bouvier.cc,2016-01-18:/kresus-version-0-7-0/</guid><category>blog</category><category>kresus</category></item><item><title>Hello Mozilla, world!</title><link>https://bouvier.cc/hello-mozilla-world/</link><description>&lt;h2 id="hello-mozilla"&gt;&lt;a class="toclink" href="#hello-mozilla"&gt;Hello Mozilla!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hello world! And in advance, happy new year!&lt;/p&gt;
&lt;p&gt;I am going to try to blog more about my work at Mozilla, and this will happen
in this new &lt;code&gt;mozilla&lt;/code&gt; category. You can expect technical posts about
SpiderMonkey (the JS virtual machine implementation in Mozilla Firefox),
OdinMonkey / asm.js, WebAssembly (wasm), and all things Mozilla in this
category.&lt;/p&gt;
&lt;p&gt;Feel free to reach me out via &lt;a href="https://twitter.com/bnjbvr"&gt;twitter&lt;/a&gt;, and see you
soon!&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Thu, 31 Dec 2015 23:59:00 +0100</pubDate><guid isPermaLink="false">tag:bouvier.cc,2015-12-31:/hello-mozilla-world/</guid><category>blog</category><category>mozilla</category></item><item><title>CozyCloud : migrer son instance 2, le retour</title><link>https://bouvier.cc/cozycloud-migrer-son-instance-2-le-retour/</link><description>&lt;p&gt;Si vous vous rappelez bien, j'ai &lt;a href="https://bouvier.cc/cozycloud-migrer-son-instance-dun-serveur-vers-un-autre/"&gt;déjà écrit un
article&lt;/a&gt;
pour expliquer comment migrer son instance &lt;a href="CozyCloud"&gt;https://cozy.io&lt;/a&gt; d'un
endroit vers un autre. Ces derniers jours, je me suis rendu compte que mon
serveur personnel était sous-utilisé et qu'il me serait possible d'en prendre
un plus léger et moins cher, d'où la nécessité d'une nouvelle migration d'un
serveur à un autre.&lt;/p&gt;
&lt;p&gt;Edit (10 février 2016) : j'ai ajouté la copie des répertoires permanents à
cette procédure, sans avoir pu tester. Vos retours sur cette partie sont les
bienvenus !&lt;/p&gt;
&lt;p&gt;Les étapes sont les suivantes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Récupérer la base de l'ancien Cozy.&lt;/li&gt;
&lt;li&gt;Recopier le répertoire de données permanentes des apps.&lt;/li&gt;
&lt;li&gt;La mettre en place dans le nouveau Cozy.&lt;/li&gt;
&lt;li&gt;Réinstaller les applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="recuperer-base-ancien-cozy"&gt;&lt;a class="toclink" href="#recuperer-base-ancien-cozy"&gt;Récupérer la base de l'ancien Cozy&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Il s'agit d'un fichier qui contient toutes les données relatives à votre Cozy,
que ce soit des données internes (par exemple, quelles applications
installées) ou propres aux applications (par exemple, vos comptes en banques).&lt;/p&gt;
&lt;p&gt;Si votre Cozy est hébergé par CozyCloud (sur
&lt;a href="https://cozycloud.cc"&gt;cozycloud.cc&lt;/a&gt; donc), il est possible de demander
l'export de la base de données CouchDB à l'équipe Cozy. Problème réglé.&lt;/p&gt;
&lt;p&gt;Si vous êtes auto-hébergé, il va falloir mettre les mains dans le cambouis :&lt;/p&gt;
&lt;p&gt;D'abord, réduire la taille de la base de données, c'est-à-dire effectuer un
compactage de la base de données. C'est parti, depuis l'ancien serveur :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# On éteint Cozy pour éviter l&amp;#39;apparition de nouvelles données&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;supervisor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# On fait une sauvegarde de la base, en cas de pépin&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;couchdb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;backup&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# On compacte la base&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;compact&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ensuite, récupérer la base elle-même. Celle-ci est contenue dans le répertoire
&lt;code&gt;/var/lib/couchdb/&lt;/code&gt; et porte le nom de &lt;code&gt;cozy.couch&lt;/code&gt;, sauf si vous l'avez
modifié vous-même.&lt;/p&gt;
&lt;h4 id="lancien-cozy-etait-installe-par-le-package-debian"&gt;&lt;a class="toclink" href="#lancien-cozy-etait-installe-par-le-package-debian"&gt;L'ancien Cozy était installé par le package Debian&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Si vous avez installé votre serveur avec le package Debian ou Ubuntu, il est
possible d'utiliser l'outil &lt;code&gt;scp&lt;/code&gt; pour effectuer cette tâche, en vous
connectant depuis le nouveau serveur vers l'ancien. Si vous utilisez cette
méthode, prenez soin de nommer la version sur le nouveau serveur
&lt;code&gt;cozy.couch.new&lt;/code&gt;, c'est important pour la suite.&lt;/p&gt;
&lt;h4 id="lancien-cozy-etait-installe-avec-docker"&gt;&lt;a class="toclink" href="#lancien-cozy-etait-installe-avec-docker"&gt;L'ancien Cozy était installé avec Docker&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Si comme moi vous avez préféré jouer avec le feu et utiliser Docker pour
installer votre cozy, il va falloir ruser un peu. Personnellement, j'ai choisi
la méthode &lt;em&gt;malpropre&lt;/em&gt;, à savoir exposer la base de données sur le serveur web
pendant un court instant et utiliser &lt;code&gt;wget&lt;/code&gt; sur le nouveau cozy. Il est
sûrement possible d'extraire le fichier depuis le Docker vers l'hôte, mais
j'avoue ne pas avoir cherché ; si quelqu'un connaît une méthode, je suis
preneur ! Pour ma méthode « malpropre », il faut modifier le fichier de
configuration de nginx pour donner accès au fichier :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# Copier la base vers /var/www&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;couchdb&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# Donner les droits en lecture à nginx&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chown&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# Editer le fichier de config de nginx avec le meilleur éditeur du monde&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vim&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;nginx&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sites&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;J'ai remplacé le bloc &lt;code&gt;location/ { proxy_set_header ...&lt;/code&gt; par le suivant :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;try_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Toujours depuis l'ancien serveur, bien penser à relancer nginx :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    sudo service nginx restart
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ensuite, depuis le nouveau serveur, sur lequel je suppose que vous avez
déjà installé le paquet &lt;code&gt;cozy&lt;/code&gt; et qu'il tourne correctement :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;couchdb&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# Stopper supervisor va arrêter tout cozy&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;supervisor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;couchdb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;monanciencozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tld&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1 id="recopier-les-donnees-permanentes-des-applications"&gt;&lt;a class="toclink" href="#recopier-les-donnees-permanentes-des-applications"&gt;Recopier les données permanentes des applications&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Cela a été rajouté depuis l'écriture initiale de ce blog post, il est donc
probable que cela ne fonctionne pas, dans quel cas contactez-moi svp !&lt;/p&gt;
&lt;p&gt;Depuis des versions récentes de la plateforme, Cozy autorise les applications à
avoir un répertoire de données permanentes, qui sont conservées même si
l'application a été désinstallée. C'est très pratique pour porter facilement
des applications qui utilisent des fichiers comme mémoire vers Cozy !&lt;/p&gt;
&lt;p&gt;Pour porter ce répertoire, voici la procédure à effectuer :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;copier le répertoire sur la machine précédente et le mettre dans un zip, par
  exemple:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# depuis la machine qui héberge l&amp;#39;ancien cozy&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;
&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;transférer le zip vers le nouveau serveur (avec votre méthode préférée : FTP,
  Web, scp, etc.). Par exemple, avec &lt;code&gt;scp&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# depuis la nouvelle machine&lt;/span&gt;
&lt;span class="n"&gt;scp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;ancienne&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;machine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;remplacer le répertoire sur la nouvelle machine:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# depuis la nouvelle machine&lt;/span&gt;
&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;
&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;backup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./*&lt;/span&gt;
&lt;span class="n"&gt;unzip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="mettre-en-place-base-nouveau-cozy"&gt;&lt;a class="toclink" href="#mettre-en-place-base-nouveau-cozy"&gt;Mettre en place la base dans le nouveau cozy&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Je suppose que vous avez déjà récupéré la base d'une manière ou d'une autre, et
que celle-ci est déjà présente dans &lt;code&gt;/var/lib/couchdb&lt;/code&gt;, sous le nom
&lt;code&gt;cozy.couch.new&lt;/code&gt;. Depuis le nouveau serveur, effectuez les commandes suivantes :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;couchdb&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;# On arrête Cozy (via supervisor) et couchdb&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;supervisor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;couchdb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;stop&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;# Backup de l&amp;#39;ancienne base&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;old&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couch&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chown&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;couchdb&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;couchdb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;./&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;couch&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;# On relance le tout&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;couchdb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;supervisor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Et voilà ! Après cela, il va falloir attendre quelques minutes que le
contrôleur Cozy relance les applications.&lt;/p&gt;
&lt;h1 id="recuperer-applications-manquantes"&gt;&lt;a class="toclink" href="#recuperer-applications-manquantes"&gt;Réinstaller les applications manquantes&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;L'import de la base comprend les données internes à Cozy, notamment les
informations sur les applications installées. Comme on vient d'importer une
base qui vient d'un autre cozy où des applications sont installées, le nouveau
cozy va penser que certaines applications sont présentes sur le disque, alors
qu'elles ne le sont pas. Il est nécessaire d'effectuer une petite réparation
ici, au niveau de la pile logicielle cozy et des applications installées.
Heureusement, l'équipe a pensé à ça et nous a fourni une commande qui permet de
réinstaller les applications utilisateurs. C'est parti, depuis le nouveau
serveur :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    &lt;span class="c1"&gt;# Mettre à jour cozy-monitor (utile pour les image préinstallées)&lt;/span&gt;
    &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;npm&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; -&lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="n"&gt;cozy-monitor&lt;/span&gt;
    &lt;span class="c1"&gt;# Mettre à jour l&amp;#39;ensemble de la pile Cozy pour commencer&lt;/span&gt;
    &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;cozy-monitor&lt;/span&gt; &lt;span class="n"&gt;update-all-cozy-stack&lt;/span&gt;
    &lt;span class="c1"&gt;# Réinstaller les applications manquantes&lt;/span&gt;
    &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;cozy-monitor&lt;/span&gt; &lt;span class="n"&gt;reinstall-missing-app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;J'ai eu plusieurs erreurs à ce moment-là, souvent liées à des applications qui
n'étaient plus trouvées sur github, ou des erreurs réseaux. En général,
relancer la commande fonctionne, sinon j'ai purement et simplement désinstallé
l'application en question. Par exemple, si l'application plantée était
&lt;a href="https://bouvier.cc/kresus-version-0-6-0/"&gt;Kresus&lt;/a&gt;, j'ai simplement effectué&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;    sudo cozy-monitor uninstall kresus
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ce n'est pas un problème, car la désinstallation d'une application n'implique
pas la désinstallation des données. Ensuite, il est possible de réinstaller les
applications depuis l'interface du site web.&lt;/p&gt;
&lt;p&gt;Pour terminer, il faut mettre à jour les permissions des dossiers contenant les
données persistantes :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;# On change les permissions pour chaque dossier. Note, penser à changer&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;# le nom de l&amp;#39;application à chaque fois&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;chown&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;nomApp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nomApp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Notons que la migration d'un serveur à l'autre est désormais beaucoup plus
facile qu'auparavant ! Pas besoin de rafistoler les données directement dans la
base, et il existe une commande pour réinstaller les applications
automatiquement. Bien joué, l'équipe Cozy !&lt;/p&gt;
&lt;p&gt;J'espère que cette procédure aura marché pour vous, j'ai écrit ces notes
rapidement et de mémoire. Si j'ai oublié quoi que ce soit, n'hésitez pas à me
contacter sur &lt;a href="https://twitter.com/bnjbvr"&gt;twitter&lt;/a&gt;,
&lt;a href="https://framasphere.org/u/bnjbvr"&gt;diaspora&lt;/a&gt; ou sur irc (mon nick est
&lt;code&gt;bnjbvr&lt;/code&gt;). Si ça a marché et que vous avez apprécié, n'hésitez pas à me le dire
également. ;-)&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Thu, 19 Nov 2015 14:00:00 +0100</pubDate><guid isPermaLink="false">tag:bouvier.cc,2015-11-19:/cozycloud-migrer-son-instance-2-le-retour/</guid><category>blog</category><category>opensource</category></item><item><title>Kresus: version 0.6.0</title><link>https://bouvier.cc/kresus-version-0-6-0/</link><description>&lt;p&gt;Je viens de publier une nouvelle version de
&lt;a href="https://github.com/bnjbvr/kresus/"&gt;Kresus&lt;/a&gt;, le gestionnaire de finances
personnelles open-source sur lequel je travaille. Pour rappel, cette
application est disponible dans &lt;a href="https://cozy.io/en/"&gt;CozyCloud&lt;/a&gt; et vous
permet de vous connecter à votre compte bancaire, récupérer vos
opérations et les classifier pour savoir où votre argent passe.&lt;/p&gt;
&lt;h4 id="lesgroschangementsdecetteversion"&gt;&lt;a class="toclink" href="#lesgroschangementsdecetteversion"&gt;Les gros changements de cette version&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Support des banques ING et HSBC (merci &lt;strong&gt;nicofrand&lt;/strong&gt; !).&lt;/li&gt;
&lt;li&gt;Libellés personnalisés : dans la liste des opérations, il est
    possible de renommer une opération en cliquant sur son libellé, en
    ajoutant des informations personnalisées dessus. Ce libellé
    personnalisé est également pris en compte dans la recherche par
    mots-clés (merci &lt;strong&gt;ZeHiro&lt;/strong&gt; !).&lt;/li&gt;
&lt;li&gt;Notifications par email : Il est maintenant possible d'envoyer des
    notifications si le solde d'un compte dépasse ou est en dessous d'un
    seuil donné; ou si une nouvelle opération dépasse un certain seuil.
    Il est également possible d'envoyer des rapports quotidiens,
    hebdomadaires ou mensuels, qui contiennent les nouvelles opérations
    importées durant la période. Plus à venir dans les prochaines
    versions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Capture de Kresus 0.6.0" src="https://bouvier.cc/img/2015-11-16_kresus-060.png"&gt;&lt;/p&gt;
&lt;h4 id="tousleschangementsdecetteversion"&gt;&lt;a class="toclink" href="#tousleschangementsdecetteversion"&gt;Tous les changements de cette version&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Merci à tous les contributeurs de cette version, que ce soit en patches
ou en rapports d'erreurs !&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ZeHiro&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;Meilleure détection des doublons (moins de faux positifs).&lt;/li&gt;
&lt;li&gt;Le tri des opérations / catégories etc. est maintenant conscient
    de la &lt;em&gt;locale&lt;/em&gt; utilisée (les accents sont pris en compte, etc.).&lt;/li&gt;
&lt;li&gt;Support des libellés personnalisés (voir ci-dessus).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;nicofrand&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;Support des champs personnalisés pour l'identification sur
    certaines banques en ligne. Certaines banques demandent la
    réponse à une question personnalisée ou la date de naissance,
    pour pouvoir s'identifier, en plus du login et du mot de passe.
    Cette contribution apporte les bases nécessaires pour supporter
    ces champs supplémentaires. En pratique, cela veut dire qu'ING
    et HSBC sont maintenant supportés par Kresus !&lt;/li&gt;
&lt;li&gt;Le bouton "vider" dans la fenêtre de recherche est maintenant en
    orange, pour alerter l'utilisateur.&lt;/li&gt;
&lt;li&gt;Ajout d'un bouton "vider et fermer" dans cette même fenêtre,
    afin de bien distinguer les deux actions : "vider" efface les
    champs du formulaire, "vider et fermer" ferme le formulaire de
    recherche.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;babolivier&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;Vérification de la présence de &lt;code&gt;virtualenv&lt;/code&gt; lors de
    l'installation de Weboob, avec fallback sur &lt;code&gt;virtualenv2&lt;/code&gt; s'il
    est présent.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dattaz&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;Ajout de &lt;code&gt;npm&lt;/code&gt; comme dépendance à l'installation Debian
    standalone&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;padenot&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;Amélioration d'une traduction de chaîne en anglais&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;rlustin&lt;/strong&gt;:&lt;ul&gt;
&lt;li&gt;Suppression des espaces en fin de ligne&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Et les autres ajouts et modifications dans Kresus :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Implémentation des rapports par emails et des alertes par email
    (voir ci-dessus).&lt;/li&gt;
&lt;li&gt;Possibilité de rechercher les libellés personnalisés, lors d'une
    recherche par mots-clés.&lt;/li&gt;
&lt;li&gt;Les imports d'instance évitent maintenant de réimporter les données
    internes à Kresus et les catégories si elles sont déjà présentes, ce
    qui évite des bugs par la suite.&lt;/li&gt;
&lt;li&gt;Kresus est capable de détecter si Weboob est installé de manière
    globale et l'utiliser de préférence, plutôt que télécharger et
    l'installer localement, si c'est possible.&lt;/li&gt;
&lt;li&gt;Le démarrage de l'application est plus séquentiel, ce qui évite des
    ralentissements au lancement (notamment pour la version standalone)
    et implique une meilleure cohérence des données.&lt;/li&gt;
&lt;li&gt;Réécriture complète du serveur, pour passer de CoffeeScript à
    ECMAScript 6. Le code est maintenant moderne, propre, plus facile à
    comprendre et n'utilise plus que JavaScript, de partout ! Cela va
    grandement faciliter les mises à jour du serveur.&lt;/li&gt;
&lt;li&gt;Comme d'habitude, beaucoup de bugs mineurs ont été écrasés et de
    plus petits nettoyages dans le code ont eu lieu.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="lesprochainschantiers"&gt;&lt;a class="toclink" href="#lesprochainschantiers"&gt;Les prochains chantiers&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Les prochains chantiers sont les choses sur lesquelles j'aimerais me
pencher pour la (les ?) prochaines versions. Bien sûr, toute
contribution sur ces sujets est plus qu'encouragée et ce sera avec
plaisir que je vous aiderai à parcourir et comprendre le code. Cela
inclut, mais ne se limite pas à :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Une réécriture partielle du code client, pour qu'il soit moins dense
    (certains fichiers font plus de 1,000 lignes !) et plus
    compartementalisé.&lt;/li&gt;
&lt;li&gt;Une meilleure gestion des erreurs affichées à l'utilisateur, pour
    qu'elles soient plus faciles à comprendre et à gérer, donc plus
    utiles.&lt;/li&gt;
&lt;li&gt;Une manière de marquer des paires d'opérations comme n'étant PAS des
    doublons, de dé-fusionner des doublons, ainsi qu'une détection
    automatique intelligente de la plupart des doublons.&lt;/li&gt;
&lt;li&gt;Une catégorisation automatique des opérations (enfin !).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="lemotdelafin"&gt;&lt;a class="toclink" href="#lemotdelafin"&gt;Le mot de la fin&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Comme d'habitude, si vous avez des remarques ou suggestions, n'hésitez
pas à me le faire savoir, par &lt;a href="https://twitter.com/bnjbvr/"&gt;twitter&lt;/a&gt; ou
sur le &lt;a href="https://forum.cozy.io/t/app-kresus/224"&gt;forum&lt;/a&gt; de cozy !&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Mon, 16 Nov 2015 10:07:00 +0100</pubDate><guid isPermaLink="false">tag:bouvier.cc,2015-11-16:/kresus-version-0-6-0/</guid><category>blog</category><category>kresus</category></item><item><title>Kresus: version 0.5.4</title><link>https://bouvier.cc/kresus-version-0-5-4/</link><description>&lt;p&gt;Je viens de publier une nouvelle version de
&lt;a href="https://github.com/bnjbvr/kresus/"&gt;Kresus&lt;/a&gt;, le gestionnaire de finances
personnelles open-source sur lequel je travaille. Pour rappel, cette
application est disponible dans &lt;a href="https://cozy.io/en/"&gt;CozyCloud&lt;/a&gt; et vous
permet de vous connecter à votre compte bancaire, récupérer vos
opérations et les classifier pour savoir où votre argent passe.&lt;/p&gt;
&lt;h4 id="nouveauts"&gt;&lt;a class="toclink" href="#nouveauts"&gt;Nouveautés&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Encore une autre mise à jour mineure avant de &lt;a href="https://github.com/bnjbvr/kresus/issues/176"&gt;gros changements
structurels&lt;/a&gt; !&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Merci &lt;a href="https://github.com/ZeHiro/"&gt;@ZeHiro&lt;/a&gt;: les types des
    opérations (carte bleue, chèque, virement, etc.), importés
    automatiquement depuis la version précédente, sont maintenant
    affichés dans l'interface et peuvent être modifiés à la main !&lt;/li&gt;
&lt;li&gt;L'interface utilisateur pour changer le type et la catégorie d'une
    opération a été améliorée : ce sont maintenant de vrais boutons qui
    permettent cela, et grâce à &lt;strong&gt;ZeHiro&lt;/strong&gt;, ces boutons sont mieux
    esthétiquement intégrés au reste de l'interface !&lt;/li&gt;
&lt;li&gt;Merci &lt;a href="https://github.com/goofy-bz"&gt;@Goofy&lt;/a&gt; pour des corrections de
    la traduction française !&lt;/li&gt;
&lt;li&gt;Merci &lt;a href="https://github.com/cylwin"&gt;@Cylwin&lt;/a&gt; qui a ajouté des liens
    vers d'autres applications Cozy (en particulier vers le connecteur
    EDF !).&lt;/li&gt;
&lt;li&gt;Merci &lt;a href="https://github.com/rgarrigue"&gt;@rgarrigue&lt;/a&gt; qui a amélioré le
    processus d'installation pour la version &lt;em&gt;standalone&lt;/em&gt; (sans Cozy).&lt;/li&gt;
&lt;li&gt;Il est maintenant possible de rechercher par type d'opération
    également. L'export contient dorénavant les types des opérations et
    l'import sait les gérer.&lt;/li&gt;
&lt;li&gt;Le fichier d'instructions
    &lt;a href="https://github.com/bnjbvr/kresus/blob/master/README.md"&gt;README&lt;/a&gt; a
    encore été étoffé ! La documentation est un travail de longue
    haleine...&lt;/li&gt;
&lt;li&gt;Et comme d'habitude, beaucoup de petits bugs ont été résolus : les
    exports sont maintenant plus solides; les opérations sont maintenant
    triées correctement dans tous les navigateurs; plus de doublons
    peuvent être trouvés; les recherches par dates sont correctes,
    &lt;a href="https://github.com/bnjbvr/kresus/commits/master"&gt;etc.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="lemotdelafin"&gt;&lt;a class="toclink" href="#lemotdelafin"&gt;Le mot de la fin&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Comme d'habitude, si vous avez des remarques ou suggestions,
n'hésitez-pas à me le faire savoir, par
&lt;a href="https://twitter.com/bnjbvr/"&gt;twitter&lt;/a&gt; ou sur le
&lt;a href="https://forum.cozy.io/t/app-kresus/224"&gt;forum&lt;/a&gt; de cozy !&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Sun, 20 Sep 2015 18:10:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2015-09-20:/kresus-version-0-5-4/</guid><category>blog</category><category>kresus</category></item><item><title>Getting Things Done: The Good Parts</title><link>https://bouvier.cc/getting-things-done-the-good-parts/</link><description>&lt;p&gt;&lt;img alt="Getting Things Done: The Good
Parts" src="https://bouvier.cc/img/2015-09-08_typewriter.jpg"&gt;&lt;/p&gt;
&lt;p&gt;I've finished the &lt;a href="http://gettingthingsdone.com/"&gt;Getting Things Done&lt;/a&gt;
book a few weeks ago and wanted to write up a bit about it, as a summary
of all the great big ideas I've found in that book.&lt;/p&gt;
&lt;h3 id="stopthejuggling"&gt;&lt;a class="toclink" href="#stopthejuggling"&gt;Stop the juggling&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It often happens that we get a lot of thoughts about plenty of things
we'd like to do later along the day. Call X. Buy Y. Think about Z. The
most common reaction to this flow of ideas is to say "alright, I'll do
it later, but I really &lt;em&gt;must&lt;/em&gt; not forget about it". That's the best way
to actually forget about this thing, to be stressed and to feel like we
should spend all our time doing it, &lt;em&gt;right now&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I really liked a metaphor I've read from the free version of the
&lt;a href="http://www.passionplanner.com/"&gt;Passion Planner&lt;/a&gt;, which was about
juggling balls. If you have one or two in your hands, it's rather easy.
With three balls, it gets a bit challenging, but you can handle that
within a few hours. Four, five, six balls, you really need to practice
before achieving it flowlessly. Seven and more? It sounds undoable to
most of us, while we actually still try to do it. How mad is that?&lt;/p&gt;
&lt;p&gt;The same thing happens with all the thoughts you have in your head.
Remembering about one or two works fine, but beyond, it's both stressing
and challenging. The solution is quite easy, though: whenever you get
distracted by a thought, &lt;strong&gt;note it down&lt;/strong&gt; on a piece of paper, any
post-it or todo-list software and get back to it later. It works fine to
have an &lt;em&gt;inbox&lt;/em&gt; list that receives all these ideas, without more
pondering or organisation.&lt;/p&gt;
&lt;p&gt;You can get to classify these things later, at some specific times and
quite regularily (e.g. at the end of the hour, day, or week, depending
on your production rate :-)).&lt;/p&gt;
&lt;h3 id="bereminded"&gt;&lt;a class="toclink" href="#bereminded"&gt;Be reminded&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Some tasks have to be done at specific dates, or can't be done right
now, or aren't urgent right now, or have to be done by other people.
Forget about them, until you can't forget about them anymore. For that
purpose, using any agenda software works like a charm: &lt;strong&gt;add a due
date&lt;/strong&gt; or a reminder to a task you have to do later, to be sure to not
forget about it.&lt;/p&gt;
&lt;p&gt;For tasks that are beyond your control (because they need actions from
somebody else), estimate how much time you're willing to wait before you
should try to get things moving forward and contact back the person
who's in charge. When you're not sure about how much, ask the task's
owner when you should get back to them. It gives a feeling of
professionalism and it gives you a date for the reminder to set in your
agenda software.&lt;/p&gt;
&lt;p&gt;Tasks that belong to this kind should be moved from the &lt;em&gt;Inbox&lt;/em&gt; to a
&lt;em&gt;Waiting For&lt;/em&gt; category of your todo-list (or binders, or anything you
want), and be forgotten until the reminder triggers.&lt;/p&gt;
&lt;h3 id="dontthrowawaythecrazyones"&gt;&lt;a class="toclink" href="#dontthrowawaythecrazyones"&gt;Don't throw away the crazy ones&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you have a stub idea for a new project, or an item you'd like to buy
but obviously not right now, or some movie or TV show you just heard
about and would like to watch in the future, &lt;strong&gt;file it&lt;/strong&gt; into your
&lt;em&gt;inbox&lt;/em&gt;. When it's time to organize things a bit, put these items into a
&lt;em&gt;Maybe/Someday&lt;/em&gt; list or sub-list. I've got for instance a list of things
I'd like to buy some day, movies I'd like to see, courses I'd like to
follow, blog posts I'd like to read, and so on: all these lists belong
to a &lt;em&gt;Maybe/Someday&lt;/em&gt; folder.&lt;/p&gt;
&lt;p&gt;Putting such things on lists also helps pondering their importance: is
that item really worth it? Is it something that I could &lt;em&gt;not&lt;/em&gt; do, &lt;em&gt;not&lt;/em&gt;
buy, &lt;em&gt;not&lt;/em&gt; watch? In particular, things you want to buy right now might
not appear as mandatory, after sitting in a list for a few months: this
really helps avoiding &lt;a href="https://en.wikipedia.org/wiki/Impulse_purchase"&gt;impulse
buyings&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Having a list full of crazy ideas is fine: the more you have, the more
you'll get, and the more chances there'll be that one of them isn't that
random.&lt;/p&gt;
&lt;h3 id="reduceprojectstothenextphysicalaction"&gt;&lt;a class="toclink" href="#reduceprojectstothenextphysicalaction"&gt;Reduce projects to the next physical action&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Where does procrastination come from? Often from our feeling of being
overwhelmed by the size of the project in front of us: we don't know
where to start or how to start. Whenever this happens to me, it often is
due to a blurry description of the thing to do. For instance, "plan
vacation" is definitely a fuzzy summary and doesn't help to understand
what's the next step to accomplish.&lt;/p&gt;
&lt;p&gt;The basic thrust is to reduce the project to the &lt;strong&gt;next physical
action&lt;/strong&gt;. What do I need to do to plan this vacation? I need to set
dates and ask my partner if they will be available at this time. Which
dates do I choose? I need to compare nights rates at several hostels,
and so on. At some point, the thinking stops and you precisely know what
your next step will be (in this example, that could be "find hostels
rates comparator websites" or "go to website X and compare rates").
That's the kind of item that should be in your todo list (and writing
down the n other steps you thought about will earn you some time).&lt;/p&gt;
&lt;h3 id="toachieveinboxzerotreatemailsliketasks"&gt;&lt;a class="toclink" href="#toachieveinboxzerotreatemailsliketasks"&gt;To achieve Inbox Zero, treat emails like tasks&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Inbox Zero is a famous productivity concept, stating that you'll have a
clearer state of mind if you get to empty your inbox: no emails means no
juggling! But that's harder than it sounds: we often inherit thousands
of emails that are in our inboxes without any form of sorting. The
initial triaging can take some time, but it's really worth it.&lt;/p&gt;
&lt;p&gt;One solution that worked for me is to &lt;strong&gt;treat emails like tasks&lt;/strong&gt;, by
categorizing them into sub-lists:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most personal emails land into my &lt;strong&gt;inbox&lt;/strong&gt;. I've used automatic
    &lt;a href="http://www.makeuseof.com/tag/set-email-filters-gmail-hotmail-yahoo/"&gt;filters&lt;/a&gt;
    for common newsletters and mundane notifications, so that they don't
    pollute the inbox.&lt;/li&gt;
&lt;li&gt;Important emails that I need to answer right now? I answer them on
    the go, and classify them right now.&lt;/li&gt;
&lt;li&gt;I've got a subfolder of my inbox that's called &lt;strong&gt;read me later&lt;/strong&gt;.
    That's for emails which don't need instantaneous action and that I
    can read later in the day / week, without any need to answer them.
    One neat trick I've read about is the &lt;em&gt;unsubscribe filter&lt;/em&gt;: set up a
    filter stating that if the email's body contains the word
    "unsubscribe", then it should be filed into the "read me later"
    directory. Most non personal emails don't land in the inbox thanks
    to this.&lt;/li&gt;
&lt;li&gt;There's a &lt;strong&gt;answer me&lt;/strong&gt; subfolder, for emails that need an answer
    but with no urge. Most personal long form emails land in this
    folder, incubate for a while and at some point I answer them, and
    that's totally fine.&lt;/li&gt;
&lt;li&gt;There's a &lt;strong&gt;waiting for&lt;/strong&gt; subfolder, with emails I've written that
    are expecting an answer. I check it once every week but having a
    reminder in the agenda software works better anyway, so I'm unsure
    about its value.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;All the other emails get archived&lt;/strong&gt;. Email providers now have
    efficient and fast search tools, so any time I need to look for
    something that belongs to the past, I just type in a few keywords
    and it works fine.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Furthermore, I also recommend looking at emails at specific times of the
day (maybe twice or three times a day, no more). Between these specific
times, I block access to the emails client in the web browser: for
Firefox, there's the great and free
&lt;a href="http://www.proginosko.com/leechblock.html"&gt;LeechBlock&lt;/a&gt; addon that
achieves this.&lt;/p&gt;
&lt;h3 id="choosethenextactionbyrequirements"&gt;&lt;a class="toclink" href="#choosethenextactionbyrequirements"&gt;Choose the next action by requirements&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are tasks that require a lot of energy to accomplish (like writing
down a report, coding, etc.) while others just need you to be a bit less
active (watching a conference video, reading new code, and so on). There
are tasks that can be done only at work, and others that can be done
only at home. Some are urgent to do before next Thursday, some could be
done maybe one day in a far, far away future. Some can be done in less
than two minutes, some others will take hours.&lt;/p&gt;
&lt;p&gt;See what's going on here? Tasks often have instrinsic caracteristics:
required energy, estimated time needed to complete, priority, location /
context. When time comes to the actual doing, it's important to
&lt;strong&gt;consider these requirements&lt;/strong&gt; and to choose accordingly.&lt;/p&gt;
&lt;p&gt;For instance, if you're starting a quite long task at the end of the
day, the chance is low that you'll finish it today. But if you feel a
need for closure, you're clearly going to overwork and stay late at
work. However, if you consider the time required to finish this task
&lt;em&gt;before&lt;/em&gt; starting it, you may not start it this day. Instead, you can
just do something shorter. That also means prioritizing your work at the
start of the day and thus not spending your time on non important stuff
as it comes.&lt;/p&gt;
&lt;h3 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There are many other ideas in the book that would need more explanation,
but if you've already read about productivity and emails management, it
should sound familiar and give yourself some insight.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://gettingthingsdone.com/fivesteps/"&gt;getting things done
website&lt;/a&gt; contains a nice
summary of the five ideas explained in the book. If you have some time,
it's nice to read it carefully, with a pair of modern eyes: some of the
tools recommended in this book looked very old-school to me (binders?
really?). I am using the &lt;a href="https://wunderlist.com/"&gt;Wunderlist&lt;/a&gt; todo
application, as it is, for me, both complete (tasks, sub-tasks, lists of
tasks, folders of lists, reminders, due dates) and minimal (nothing else
that make it overly complicated).&lt;/p&gt;
&lt;p&gt;Thanks for reading. If you have any comment or remark, feel free to drop
me a line on &lt;a href="https://twitter.com/bnjbvr"&gt;twitter&lt;/a&gt;! If you've
appreciated the blog post, don't hesitate to let me know and skim the
rest of the blog posts ;-)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;a href="https://pixabay.com/en/typewriter-book-notebook-paper-801921/"&gt;Picture by Unsplash, published under CC0 Public
Domain&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Tue, 08 Sep 2015 08:00:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2015-09-08:/getting-things-done-the-good-parts/</guid><category>blog</category><category>life</category></item><item><title>Kresus : version 0.5.3</title><link>https://bouvier.cc/kresus-version-0-5-3/</link><description>&lt;p&gt;Je viens de publier une nouvelle version de
&lt;a href="https://github.com/bnjbvr/kresus/"&gt;Kresus&lt;/a&gt;, le gestionnaire de finances
personnelles open-source sur lequel je travaille. Pour rappel, cette
application est disponible dans &lt;a href="https://cozy.io/en/"&gt;CozyCloud&lt;/a&gt; et vous
permet de vous connecter à votre compte bancaire, récupérer vos
opérations et les classifier pour savoir où votre argent passe.&lt;/p&gt;
&lt;h4 id="actionrequise"&gt;&lt;a class="toclink" href="#actionrequise"&gt;Action requise&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Une action est requise de votre part, suite à cette mise à jour, &lt;strong&gt;si la
synchronisation ne marche plus&lt;/strong&gt;, ou si votre balance ne correspond pas
à celle indiquée par votre site de banque :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Aller dans Préférences.&lt;/li&gt;
&lt;li&gt;Aller dans l'onglet Gestion de Weboob.&lt;/li&gt;
&lt;li&gt;Cliquer sur le bouton pour mettre à jour Weboob.&lt;/li&gt;
&lt;li&gt;Aller dans l'onglet Comptes bancaires.&lt;/li&gt;
&lt;li&gt;Cliquer sur le bouton de synchronisation des comptes (flèches
    imbriquées).&lt;/li&gt;
&lt;li&gt;Vérifier et traiter les doublons, dans l'onglet correspondant.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="nouveauts"&gt;&lt;a class="toclink" href="#nouveauts"&gt;Nouveautés&lt;/a&gt;&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Merci &lt;a href="https://github.com/ZeHiro/"&gt;@ZeHiro&lt;/a&gt;: Import des types
    d'opérations bancaires en base (est-ce que l'opération est une carte
    bleue, un chèque, un virement, etc.). Pas encore d'affichage, mais
    c'est &lt;a href="https://github.com/bnjbvr/kresus/pull/175"&gt;pour bientôt&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Merci @ZeHiro: quand une opération est associée à un fichier, le nom
    et le type du fichier joint sont correctement associés.&lt;/li&gt;
&lt;li&gt;Merci @ZeHiro: la balance de chaque compte est maintenant affichée
    dans le menu de sélection des comptes.&lt;/li&gt;
&lt;li&gt;Merci &lt;a href="https://github.com/cylwin/"&gt;@cylwin&lt;/a&gt;: l'IBAN est maintenant
    importé avec chaque compte. Cela n'est pas encore visible dans
    l'interface, mais j'ai quelques idées pour rendre cette information
    utile.&lt;/li&gt;
&lt;li&gt;Merci &lt;a href="https://github.com/nicofrand/"&gt;@nicofrand&lt;/a&gt; pour quelques
    accents manquants dans la traduction française.&lt;/li&gt;
&lt;li&gt;Ajout d'un bouton pour mettre à jour Weboob, sans avoir à le
    réinstaller entièrement, ce qui permet des mises à jour plus
    rapides.&lt;/li&gt;
&lt;li&gt;Ajout de fonctionnalités d'import / export d'une instance Kresus
    (c'est-à-dire toutes les banques, tous les comptes, toutes les
    opérations, toutes les catégories, etc.). Notez que le mot de passe
    n'est pas inclus dans l'export, pour des raisons évidentes de
    sécurité, et qu'il sera donc nécessaire de le remettre à la main
    dans l'onglet préférences après un import.&lt;/li&gt;
&lt;li&gt;Affichage d'un message d'erreur explicite si le mot de passe est
    incorrect, lors d'une synchronisation manuelle.&lt;/li&gt;
&lt;li&gt;Kresus peut maintenant &lt;a href="https://github.com/bnjbvr/kresus/#on-debian"&gt;s'installer et être lancé en dehors de
    CozyCloud&lt;/a&gt;, sans aucune
    dépendence à Cozy. Pour le moment, c'est très instable et pas
    recommandé : il n'y a aucune protection par mot de passe, beaucoup
    de risques de sécurité, des fonctionnalités sont manquantes (pas de
    notifications, pas d'emails d'alertes, etc.). Je reviendrai plus en
    détail dessus quand la version standalone sera prête.&lt;/li&gt;
&lt;li&gt;Fusion des comptes similaires : lorsque une banque change son site,
    il se peut que les comptes ne soient plus identifiés de la même
    manière ; Kresus est maintenant capable de s'en rendre compte et
    d'effectuer la maintenance nécessaire.&lt;/li&gt;
&lt;li&gt;Le fichier
    &lt;a href="https://github.com/bnjbvr/kresus/blob/master/README.md"&gt;README&lt;/a&gt; a
    été grandement amélioré et un code de conduite générique a été
    ajouté au projet.&lt;/li&gt;
&lt;li&gt;Beaucoup d'améliorations de code interne (refactoring), patches pour
    des petits bugs (notamment le tri hasardeux des opérations devrait
    être réglé), le processus de développement a été grandement
    simplifié également.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="lemotdelafin"&gt;&lt;a class="toclink" href="#lemotdelafin"&gt;Le mot de la fin&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Comme d'habitude, si vous avez des remarques ou suggestions,
n'hésitez-pas à me le faire savoir, par
&lt;a href="https://twitter.com/bnjbvr/"&gt;twitter&lt;/a&gt; ou sur le
&lt;a href="https://forum.cozy.io/t/app-kresus/224"&gt;forum&lt;/a&gt; de cozy !&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Tue, 01 Sep 2015 12:16:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2015-09-01:/kresus-version-0-5-3/</guid><category>blog</category><category>kresus</category></item><item><title>Kresus : version 0.5.2</title><link>https://bouvier.cc/kresus-version-0-5-2-2/</link><description>&lt;p&gt;Je viens de publier une nouvelle version de
&lt;a href="https://github.com/bnjbvr/kresus"&gt;Kresus&lt;/a&gt;, le gestionnaire de finances
personnelles open-source sur lequel je travaille. Pour rappel, cette
application est disponible uniquement dans &lt;a href="https://cozy.io"&gt;CozyCloud&lt;/a&gt;
(pour l'instant) et vous permet de vous connecter à votre compte
bancaire, récupérer vos opérations et les classifier pour savoir où
votre argent passe.&lt;/p&gt;
&lt;p&gt;Mise à jour mineure, car elle concerne principalement des bugs qui ont
été réglés au cours de cette version :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;La fusion des opérations similaires n'oublie plus les fichiers
    associés.&lt;/li&gt;
&lt;li&gt;Les notifications de nouvelles opérations ne devraient plus être
    envoyées en doublons dorénavant.&lt;/li&gt;
&lt;li&gt;Si un compte de votre banque n'est pas supporté par Kresus, cela
    n'empêchera plus les autres comptes d'être supportés correctement.&lt;/li&gt;
&lt;li&gt;Ajout d'une section "à propos" dans les préférences.&lt;/li&gt;
&lt;li&gt;Beaucoup d'autres petits bugs ont été réglés.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Merci à ZeHiro et poupotte pour leurs contributions ainsi qu'à tous ceux
qui ont fait des rapports de bugs !&lt;/p&gt;
&lt;p&gt;Comme d'habitude, si vous avez des remarques ou suggestions,
n'hésitez-pas à me le faire savoir, par twitter ou sur le &lt;a href="https://forum.cozy.io/t/app-kresus/224"&gt;forum de
cozy&lt;/a&gt; !&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Sun, 12 Jul 2015 14:08:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2015-07-12:/kresus-version-0-5-2-2/</guid><category>blog</category><category>kresus</category></item><item><title>Des idées folles pour faciliter le développement sous Cozy</title><link>https://bouvier.cc/des-idees-folles-pour-faciliter-le-developpement-sous-cozy/</link><description>&lt;p&gt;Récemment, sur le forum de CozyCloud,
&lt;a href="https://twitter.com/Clochix"&gt;Clochix&lt;/a&gt;
(employé de l'entreprise CC), demandait comment l'on pourrait faciliter
le développement d'applications pour Cozy. Bonne initiative ! J'ai
essayé de structurer un peu mes idées dans le forum d'abord, mais comme
ça devenait beaucoup trop long, j'ai préféré écrire ce post, vu que j'ai
beaucoup de commentaires :)&lt;/p&gt;
&lt;p&gt;Parmi ces commentaires, il y a beaucoup d'idées saugrenues, sûrement
difficiles à implémenter, mais je fais le pari que si je les écris ici,
elles pourront inspirer les lecteurs, qui crééeront leurs propres idées
à partir de celles-ci, ou en les fusionnant, etc. Les idées
appartiennent à tout le monde !&lt;/p&gt;
&lt;h3 id="dustatique"&gt;&lt;a class="toclink" href="#dustatique"&gt;Du statique&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Tout d'abord, il me semble primordial de permettre de développeur sur
son cozy depuis son cozy. Pour commencer, on pourrait partir avec &lt;strong&gt;un
site statique et un éditeur de texte&lt;/strong&gt;. Imaginons un instant un
répertoire spécial &lt;code&gt;www&lt;/code&gt; par exemple, accessible depuis Files. Une
nouvelle application ferait office de serveur statique, et pourrait
servir tous les fichiers présents dans ce répertoire &lt;code&gt;www&lt;/code&gt; sur une
adresse publique. Ensuite, une autre application saurait ouvrir tous les
fichiers textes importés dans Files et les éditer directement. Avec ces
deux choses, on a la possibilité de &lt;strong&gt;créer son site statique et le
modifier directement depuis son cozy&lt;/strong&gt;. Cela me paraît une bonne
première étape !&lt;/p&gt;
&lt;p&gt;L'intégration d'outils comme &lt;a href="https://webmaker.org"&gt;WebMaker&lt;/a&gt; pourrait
même permettre de créer des sites facilement pour les débutants, et de
propager l'apprentissage des technologies web auprès du grand public.&lt;/p&gt;
&lt;h3 id="desoutilsdedveloppement"&gt;&lt;a class="toclink" href="#desoutilsdedveloppement"&gt;Des outils de développement&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ensuite, &lt;a href="https://forum.cozy.io/t/comment-pouvons-nous-vous-aider-a-bidouiller-cozy/880/2?u=ben"&gt;comme le dit
@Clochix&lt;/a&gt;,
&lt;strong&gt;réduire le nombre d'outils à utiliser pour le développement&lt;/strong&gt;. A
l'heure actuelle, quand je veux modifier
&lt;a href="https://github.com/bnjbvr/kresus"&gt;Kresus&lt;/a&gt; (mon application de finances
personnelles hébergée sur cozy) depuis ma machine de tous les jours, je
dois :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;lancer la VM de développement dans le bon répertoire, ce qui prend
    facilement 2 minutes (vérification de l'image, timeouts
    malheureusement réguliers sur le SSH, etc.)&lt;/li&gt;
&lt;li&gt;aller dans le répertoire de Kresus depuis la machine hôte&lt;/li&gt;
&lt;li&gt;lancer &lt;code&gt;cozy-dev deploy 9876&lt;/code&gt; (parce que le cozy de dev ne se
    souvient pas que j'ai pu faire un deploy auparavant... peut-être que
    ça vaut un bug ?). C'est instantané, mais c'est redondant de le
    faire à chaque fois !&lt;/li&gt;
&lt;li&gt;lancer kresus&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Si jamais je veux modifier kresus depuis une nouvelle machine, je dois
en plus de ça télécharger et installer la VM (ce qui peut facilement
prendre 10 minutes, en fonction du débit et de la puissance de la
machine).&lt;/p&gt;
&lt;p&gt;Dans un monde idéal de développement d'applications pour Cozy,
j'aimerais avoir à faire simplement :&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;lancer kresus&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;C'est-à-dire qu'il y ait une machine toute prête pour le développement.
Peu m'importe l'implémentation :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;que ce soit via le serveur de production, qui utiliserait une
    deuxième base couchdb (si cette notion a du sens ?) pour ne pas
    écraser les données de l'instance de production;&lt;/li&gt;
&lt;li&gt;que ce soit via &lt;a href="https://c9.io/"&gt;cloud9&lt;/a&gt; ou tout autre système de
    dév avec VM intégrée en ligne;&lt;/li&gt;
&lt;li&gt;que ce soit via une app de VM sur le cozy (qemu.js, quelqu'un ?);&lt;/li&gt;
&lt;li&gt;[insérez d'autres idées folles ici];&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Allons plus loin : si j'ai la possibilité d'avoir un éditeur de code
directement dans cozy (coucou
&lt;a href="https://github.com/coolwanglu/vim.js"&gt;vim.js&lt;/a&gt;), pourquoi ne pas
modifier à la volée mes apps, côté client comme côté serveur, et
recharger directement depuis le cozy ? Cela permettrait d'avoir des
retours encore plus rapides sur le processus de développement (et de
trouver plein de bugs de cozy-controller, si jamais il en y avait
certain de bien planqués !).&lt;/p&gt;
&lt;h3 id="duportage"&gt;&lt;a class="toclink" href="#duportage"&gt;Du portage&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Je désigne par portage le fait de prendre du code d'une app déjà
existante et d'essayer de le porter sous Cozy.&lt;/p&gt;
&lt;p&gt;Pour moi, le plus gros problème du portage est sûrement le fait qu'il
faille &lt;strong&gt;réécrire toutes les URLs&lt;/strong&gt;, côté client. De nos jours, assez
souvent, les applications web supposent qu'elles ont accès à un domaine
ou un sous-domaine entier, et pas qu'elles vont vivre dans un
sous-répertoire particulier (sauf en PHP, sigh). Par exemple, le système
de blog Ghost suppose qu'il vit dans &lt;code&gt;http://ghost.example.com&lt;/code&gt;, pas
dans &lt;code&gt;http://example.com/ghost&lt;/code&gt;, sauf contre-indication. Du coup, la
plupart des URLs doivent être réécrites, et c'est souvent assez
difficile ou obscur de trouver où sont ces dernières.&lt;/p&gt;
&lt;p&gt;Bien sûr, il y a des solutions :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;un sous-domaine par app, mais ça pose des problèmes pour les
    certificats SSL vu qu'il faut des certificats avec &lt;em&gt;wildcard&lt;/em&gt; sur
    les sous-domaines, mais heureusement &lt;a href="https://letsencrypt.org/2015/06/16/lets-encrypt-launch-schedule.html"&gt;LetsEncrypt devrait sortir en
    septembre&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;utilisation de &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorker"&gt;service
    workers&lt;/a&gt;
    pour réécrire toutes les URLs commandées par le client, côté client
    : beurk, mais efficace;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;L'autre problème du portage est &lt;strong&gt;l'intégration des données&lt;/strong&gt; : même
s'il est &lt;em&gt;faisable&lt;/em&gt; d'intégrer les données d'apps existantes pour
qu'elles vivent dans le couchdb du cozy (voir dernière partie), cela
n'assure pas de créer facilement des interactions entre les données des
apps existantes et des apps portées. Quand bien même l'on voudrait
rajouter ces interactions, il faut modifier l'interface utilisateur de
l'app portée (difficile), ou bien le faire depuis une autre app (étrange
en termes d'interaction utilisateur). Le portage n'est pas un problème
simple (et ce n'est vraiment pas la faute de Cozy, c'est inhérent à tous
les clouds personnels, à mon avis).&lt;/p&gt;
&lt;h3 id="deschoixtechnologiques"&gt;&lt;a class="toclink" href="#deschoixtechnologiques"&gt;Des choix technologiques&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://blog.menfin.info/posts/2015-07-01-sur-un-petit-nuage-cozy/"&gt;Le blog de
N`&lt;/a&gt;
lit : "[...] je regrette certains choix techniques et les conséquences
associées. CouchDB n’est plus très populaire ces derniers temps.". A
vrai dire, quelle que fût la technologie utilisée comme backend, on
aurait pu trouver ces remarques, avec "postgre", ou "mongo", ou
n'importe quel autre produit à la place de "couchdb". Et ce n'est pas
que la dite technologie est mauvaise, loin de là ; c'est simplement que
les différents auteurs d'app voudront utiliser des technologies
différentes.&lt;/p&gt;
&lt;p&gt;Personnellement, l'utilisation de CouchDB m'a demandé un effort initial
(à cause du système de vues) que ne m'aurait pas demandé une bête base
de données SQL. Ce n'est pas pour autant quelque chose de difficile,
mais c'est quelque chose de nouveau, et l'amas de nouveaux concepts liés
au développement dans Cozy peut être un frein.&lt;/p&gt;
&lt;p&gt;Et qu'il s'agisse de la base de données ou du langage, le problème dans
les deux cas est la dispersion : plus d'outils, ça signifie plus de
maintenance nécessaire, plus de vecteurs d'attaques, etc. Pourtant,
combien de personnes adoreraient développer une app pour Cozy, mais ne
le font pas parce qu'il n'est pas possible d'écrire sa web app en
Python, Erlang, Haxe, allez soyons fous, PHP ? Combien de projets ne
sont pas portés, pour les mêmes raisons ? Avec la mode de la
containerisation, sandboxer un interpréteur ou une VM est quasiment
gratuit et pourrait permettre cette utilisation d'autres langages dans
Cozy.&lt;/p&gt;
&lt;p&gt;Pour le problème de la base de données, il y a plusieurs approches :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;juste installer plusieurs systèmes de gestion de base de données
    dans la plateforme (mongo, cassandra, whatever), mais ce n'est
    vraiment pas idéal, pour les raisons exposées ci-dessus;&lt;/li&gt;
&lt;li&gt;utiliser un protocole de stockage de données indépendant du langage,
    l'implémenter dans cozy puis écrire quelques bibliothèques de code
    réutilisables pour pouvoir utiliser ce protocole. C'est l'approche
    prise par ces bons gars de Mozilla avec
    &lt;a href="http://kinto.readthedocs.org/"&gt;Kinto&lt;/a&gt;, comme expliqué
    &lt;a href="http://www.servicedenuages.fr/stockage-generique-ecosysteme"&gt;ici&lt;/a&gt;.
    En y réfléchissant bien, c'est &lt;em&gt;presque&lt;/em&gt; l'approche prise par le
    système de données dans Cozy, vu qu'il utilise des appels à un point
    d'accès HTTP : la seule différence réside dans le fait que ces
    appels sentent et rappellent trop Couch;&lt;/li&gt;
&lt;li&gt;écrire un meta-adaptateur : une application qui comprenne les
    protocoles de plusieurs bases de données (de manière à ce que
    l'utilisateur puisse avoir l'impression de communiquer avec par
    exemple mongo, ou mariadb, indifféremment), et qui retranscrive cela
    en structures de données et requêtes couchdb. Je pense que c'est
    illusoire : vu que les différents systèmes de stockage peuvent
    assurer différentes parties du théorème CAP, beaucoup de
    fonctionnalités pourraient ne pas être équivalentes (ou ne pas être
    imitées de manière efficace).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="decequimarche"&gt;&lt;a class="toclink" href="#decequimarche"&gt;De ce qui marche&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Les mêmes problèmes se posent pour d'autres plateformes de cloud
personnel comme &lt;a href="http://owncloud.com/"&gt;OwnCloud&lt;/a&gt; et ne vont pas se
résoudre du jour au lendemain. Chacune de ces idées demande un temps
d'implémentation considérable (sauf peut-être le serveur statique et
l'éditeur de texte -- à croire que c'en est une bonne idée !), du temps
pour tester de la part des utilisateurs et beaucoup de retours entre
développeurs et utilisateurs. Pourtant, certains ont déjà été confrontés
à ces problématiques et les ont résolues avec panache.&lt;/p&gt;
&lt;p&gt;Un modèle en la matière est &lt;a href="http://app.net/"&gt;App.net&lt;/a&gt; (ADN pour les
intimes), un réseau social &lt;em&gt;centralisé&lt;/em&gt; mais qui assure de ne pas
espionner les données des utilisateurs, en contrepartie d'un abonnement
de quelques dollars par mois. Des apps pour ADN peuvent être créées par
les utilisateurs très facilement, et il en existe de très bonnes.
Qu'est-ce qui a attiré les développeurs pour créer des apps pour ADN ?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;une &lt;a href="https://developers.app.net/docs/"&gt;documentation exemplaire&lt;/a&gt;,
    avec de nombreux tutoriels, des présentations de l'API, plein de
    liens vers différents canaux de communications réservés aux
    développeurs, des articles de blog juste pour présenter des
    nouvelles APIs aux développeurs, des podcasts, etc. La documentation
    est open-source et peut être modifiée par n'importe qui, comme pour
    Cozy.&lt;/li&gt;
&lt;li&gt;une &lt;a href="http://blog.app.net/2013/11/18/adnpy-a-new-python-library-from-app-net/"&gt;diversité au niveau des
    technologies&lt;/a&gt;
    utilisées pour écrire des apps clientes pour ADN : python, objective
    c, android, etc.;&lt;/li&gt;
&lt;li&gt;l'&lt;a href="http://blog.app.net/2014/01/27/app-net-hackathon-recap-3/"&gt;organisation de
    hackathons&lt;/a&gt;
    pour lancer des projets en commun, faire se rencontrer des
    développeurs et provoquer le démarrage de nouvelles apps;&lt;/li&gt;
&lt;li&gt;des articles de blog &lt;a href="http://blog.app.net/2014/01/17/sunlit/"&gt;présentant des nouvelles apps pour
    ADN&lt;/a&gt; (n.b.: kresus n'a pas
    encore atteint ce niveau de maturité à mon avis);&lt;/li&gt;
&lt;li&gt;encore plus fou, &lt;a href="http://blog.app.net/2013/03/01/updates-to-the-app-net-developer-incentive-program/"&gt;un programme d'incentives pour le développement
    d'app&lt;/a&gt;.
    En gros, si votre application a été sélectionnée comme étant une des
    plus utiles à la communauté, vous recevez une part d'un budget
    alloué à la promotion du développement des nouvelles apps. C'est un
    argument pécunier, mais c'est sûrement ce qui a fait la différence
    entre ADN et &lt;a href="https://tent.io"&gt;tent&lt;/a&gt;, par exemple (tent est mort,
    vite tent).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A mon avis, les trois premiers points demandent un investissement
relativement mineur et permettraient de donner un coup de pied au
développement d'apps sous Cozy. Par ailleurs,
&lt;a href="https://github.com/bnjbvr/kresus"&gt;Kresus&lt;/a&gt; cherche toujours de nouveaux
contributeurs, si vous êtes intéressés, n'hésitez-pas à me contacter !&lt;/p&gt;
&lt;p&gt;Si vous avez des remarques par rapport à cet article, je vous invite à
m'en faire part sur &lt;a href="https://twitter.com/bnjbvr"&gt;twitter&lt;/a&gt; pour les
remarques courtes ou sur &lt;a href="https://forum.cozy.io/t/comment-pouvons-nous-vous-aider-a-bidouiller-cozy/"&gt;le
forum&lt;/a&gt;
pour les remarques plus longues. Cheers !&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Tue, 07 Jul 2015 18:37:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2015-07-07:/des-idees-folles-pour-faciliter-le-developpement-sous-cozy/</guid><category>blog</category><category>opensource</category></item><item><title>Kresus : version 0.5.1</title><link>https://bouvier.cc/kresus-version-0-5-1/</link><description>&lt;p&gt;Je viens de publier une nouvelle version de
&lt;a href="https://github.com/bnjbvr/kresus"&gt;Kresus&lt;/a&gt;, le gestionnaire de finances
personnelles open-source sur lequel je travaille. Pour rappel, cette
application est disponible uniquement dans &lt;a href="https://cozy.io"&gt;CozyCloud&lt;/a&gt;
(pour l'instant) et vous permet de vous connecter à votre compte
bancaire, récupérer vos opérations et les classifier pour savoir où
votre argent passe.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Graphiques" src="https://bouvier.cc/img/2015-05-09_kresus-051.png"&gt;&lt;/p&gt;
&lt;p&gt;Parmi les nouveautés :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Meilleurs graphiques : il est possible d'afficher des graphiques des
    opérations par catégories par mois, sur des périodes données (tout
    le temps, mois courant, mois précédent, 3 derniers mois, 6 derniers
    mois), pour des types d'opérations données (toutes, dépenses ou
    revenus uniquement). De plus, des graphiques en "camembert" sont
    maintenant générés si l'on regarde les dépenses ou les revenus.&lt;/li&gt;
&lt;li&gt;Il est également possible de choisir quelle période et quel type
    d'opérations s'affichent par défaut (depuis les Préférences
    avancées).&lt;/li&gt;
&lt;li&gt;La gestion des opérations en doublons a été améliorée : maintenant,
    c'est l'application qui choisit lequel des deux doublons il est
    nécessaire de supprimer. Ainsi, on ne parle plus de suppression de
    doublons mais de
    &lt;a href="https://www.youtube.com/watch?v=JatzJYDqfAE"&gt;FUSION&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Utilisation de Dygraph et c3 pour la partie graphiques, ce qui fait
    que Kresus ne dépend plus de Highcharts, dont la license pouvait
    poser problème au sein de CozyCloud.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Comme d'habitude, si vous avez des remarques ou suggestions,
n'hésitez-pas à me le faire savoir, par twitter ou sur le &lt;a href="https://forum.cozy.io/t/app-kresus/224"&gt;forum de
cozy&lt;/a&gt; !&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Sat, 09 May 2015 17:38:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2015-05-09:/kresus-version-0-5-1/</guid><category>blog</category><category>kresus</category></item><item><title>Wallabag, mot de passes, sel et empreintes</title><link>https://bouvier.cc/wallabag-changer-mot-de-passe-perdu/</link><description>&lt;h1 id="changersonmotdepassewallabagtldr"&gt;&lt;a class="toclink" href="#changersonmotdepassewallabagtldr"&gt;Changer son mot de passe Wallabag, TL:DR;&lt;/a&gt;&lt;/h1&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/var/www/wallabag
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;printf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;motdepasseLogin&amp;quot;&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;inc/poche/config.inc.php&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SALT&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cut&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;openssl&lt;span class="w"&gt; &lt;/span&gt;sha1
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;c87c3d3f823c166602a0ddfc2d96c82aa7b27d9e
$&lt;span class="w"&gt; &lt;/span&gt;sqlite3&lt;span class="w"&gt; &lt;/span&gt;db/poche.sqlite
sqlite&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;update&lt;span class="w"&gt; &lt;/span&gt;users&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;c87c3d3f823c166602a0ddfc2d96c82aa7b27d9e&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;where&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
sqlite&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;^D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1 id="commentchangersonmotdepassewallabagladure"&gt;&lt;a class="toclink" href="#commentchangersonmotdepassewallabagladure"&gt;Comment changer son mot de passe Wallabag, à la dure&lt;/a&gt;&lt;/h1&gt;
&lt;h5 id="akacommentperdresonmotdepassewallabagenpremierlieu"&gt;&lt;a class="toclink" href="#akacommentperdresonmotdepassewallabagenpremierlieu"&gt;aka, comment perdre son mot de passe Wallabag en premier lieu&lt;/a&gt;&lt;/h5&gt;
&lt;p&gt;&lt;img alt="Wallabag, mot de passes, sel et
empreintes" src="https://bouvier.cc/img/2015-05-06_kangourou.jpeg"&gt;&lt;/p&gt;
&lt;p&gt;J'utilise &lt;a href="http://wallabag.org/"&gt;Wallabag&lt;/a&gt;, un service de liste de
lecture libre et décentralisé, donc un concurrent de
&lt;a href="https://getpocket.com/"&gt;Pocket&lt;/a&gt; et &lt;a href="http://alternativeto.net/software/read-it-later/"&gt;autres
alternatives&lt;/a&gt;, que je
recommande particulièrement pour son efficacité et sa simplicité. En
particulier, j'utilise une &lt;a href="https://registry.hub.docker.com/u/bobmaerten/docker-wallabag/"&gt;image
Docker&lt;/a&gt;
prête à l'usage, pour éviter d'avoir à installer &lt;code&gt;php&lt;/code&gt; directement sur
mon serveur. Tout allait bien, jusqu'à que je redémarre le container :
il m'était alors impossible de me reconnecter. En fouillant un peu, je
me rends compte qu'il y a un sel utilisé pour le hash des mots de passe,
et qu'il est possible que ce sel ait changé suite au redémarrage du
docker (si vous avez cliqué sur le lien du docker registry ci-dessus,
vous verrez qu'il est recommandé de définir ce sel comme une variable
d'environnement, ce que j'avais bien sûr omis). Dans ce cas-là, je me
suis trouvé bloqué hors de mon Wallabag, avec aucune possibilité de
changer le mot de passe (ou de m'envoyer un email de récupération de
compte), ce qui revient à perdre ses données.&lt;/p&gt;
&lt;h2 id="duselpourlehashmaisbiensr"&gt;&lt;a class="toclink" href="#duselpourlehashmaisbiensr"&gt;Du sel pour le hash ? Mais bien sûr !&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Petite explication technique pour ceux qui veulent savoir de quoi on
parle ici. Si sel, hash et SHA1 n'ont pas de secrets pour vous, vous
pouvez passer à la suite.&lt;/p&gt;
&lt;p&gt;Il est dangereux de sauvegarder des mots de passe utilisateur en base de
données, en clair : sinon, cela signifie que les administrateurs du site
ou d'éventuels pirates peuvent s'authentifier sur le compte de
l'utilisateur et accéder à toutes ses données. De telles fuites de mots
de passe ont lieu assez couramment. Pour éviter cela, plutôt que stocker
le mot de passe en clair dans une base de données, on utilise une
fonction mathématique à sens unique qui transforme le mot de passe à
l'aide d'une formule mathématique compliquée en une "empreinte"
numérique. Cela signifie qu'il est facile de calculer l'empreinte à
partir du mot de passe, mais qu'il est (théoriquement) compliqué de
retrouver le mot de passe à partir de l'empreinte.&lt;/p&gt;
&lt;p&gt;Du coup, plutôt que stocker le mot de passe en clair dans la base de
données, on stocke l'empreinte générée dans la base. Ainsi, pour
vérifier si un mot de passe entré par l'utilisateur sur le site est le
bon, il suffit de générer l'empreinte du mot de passe entré sur le site,
et de comparer avec l'empreinte en base de données. Jusque là, tout va
bien.&lt;/p&gt;
&lt;p&gt;Tout va bien, sauf si la fonction mathématiquement théoriquement
compliquée ne l'est pas tant que ça. Pour Wallabag, il s'agit de SHA1,
qui a été prouvée comme étant facilement cassable il y a quelques années
de ça déjà. Il y a une très bonne
&lt;a href="http://stackoverflow.com/questions/2772014/is-sha-1-secure-for-password-storage"&gt;explication&lt;/a&gt;
ici de la méthode utilisée pour retrouver le mot de passe à partir de
l'empreinte. L'idée est de prendre beaucoup de temps à générer des
tables avec toutes les entrées possibles, de manière à avoir une table
de correspondances entrées / empreintes, et ensuite quand on a une
empreinte donnée, de comparer à celles qui étaient présentes dans la
table avec toutes les correspondances.&lt;/p&gt;
&lt;p&gt;Pour contrer cette attaque, il suffit de rajouter un "sel" après le mot
de passe, c'est-à-dire une chaîne de caractères compliquée, connue
uniquement par l'application elle-même. Ainsi, les attaques par table de
correspondance sont (encore une fois, théoriquement) impossibles, car
l'attaquant ne connaît pas le "sel" rajouté.&lt;/p&gt;
&lt;h2 id="etlelienavecleschmilblick"&gt;&lt;a class="toclink" href="#etlelienavecleschmilblick"&gt;Et le lien avec le Schmilblick ?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Dans mon instance de Wallabag, le sel rajouté au mot de passe a été
modifié en redémarrant le container docker, ce qui fait que l'empreinte
que je générais en essayant de me connecter ne correspondait plus à
celle en base de données. Du coup, la solution pour s'en sortir est de
regénérer cette empreinte et la réécrire directement dans la base de
données. Comment faire ?&lt;/p&gt;
&lt;p&gt;Heureusement, le code de Wallabag étant open-source, j'ai pu le
consulter sur &lt;a href="https://github.com/wallabag/wallabag"&gt;github&lt;/a&gt;. En
particulier, en faisant une &lt;a href="https://github.com/wallabag/wallabag/search?utf8=%E2%9C%93&amp;amp;q=SALT"&gt;recherche sur
SALT&lt;/a&gt;,
j'ai trouvé &lt;a href="https://github.com/wallabag/wallabag/blob/master/inc/poche/config.inc.default.php#L11"&gt;cette
ligne&lt;/a&gt;
qui définit le sel rajouté pour calculer l'empreinte :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;@define&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;SALT&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;put&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;strong&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il suffit donc de regarder la valeur écrite en dur dans ce fichier.
Valeur qui est par ailleurs
&lt;a href="https://github.com/wallabag/wallabag/blob/4b1fa4c2febc7abbc6da3d65e4e760949a55843c/install/index.php#L66"&gt;utilisée&lt;/a&gt;
au moment de l'installation pour générer l'empreinte du mot de passe en
base de données :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$salted_password = sha1($password . $username . $salt);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Donc l'empreinte est générée à partir de la chaîne de caractères
suivante : mot de passe, nom d'utilisateur, sel trouvé dans le fichier
&lt;code&gt;inc/poche/config.inc.default.php&lt;/code&gt;, le tout sans espaces. Il suffit donc
maintenant de retrouver le sel, regénérer l'empreinte et mettre à jour
la base de données, ce qui se fait en 5 lignes, comme le montre la
section TL:DR ci-dessus.&lt;/p&gt;
&lt;h2 id="conclusiongometa"&gt;&lt;a class="toclink" href="#conclusiongometa"&gt;Conclusion : go meta&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Cette méthode de génération d'empreintes pour stocker des mots de passe
en base de données est assez récurrente, du coup il est possible de
l'adapter à d'autres algorithmes (SHA256) et d'autres constructions de
chaînes.&lt;/p&gt;
&lt;p&gt;Bien sûr, pour ce qui est du Docker Wallabag, il est plus simple de
définir le sel comme une variable d'environnement, comme indiqué dans la
documentation du container.&lt;/p&gt;
&lt;p&gt;Par ailleurs, s'il existe une autre méthode pour récupérer son mot de
passe sous Wallabag, je serai ravi de la connaître ! N'hésitez pas à me
faire part de vos remarques via &lt;a href="https://twitter.com/bnjbvr"&gt;twitter&lt;/a&gt;.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Wed, 06 May 2015 19:53:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2015-05-06:/wallabag-changer-mot-de-passe-perdu/</guid><category>blog</category><category>opensource</category></item><item><title>CozyCloud : migrer son instance d'un serveur vers un autre</title><link>https://bouvier.cc/cozycloud-migrer-son-instance-dun-serveur-vers-un-autre/</link><description>&lt;p&gt;Il arrive de temps en temps de devoir changer de serveur, et puisque le
credo de &lt;a href="http://cozy.io/"&gt;CozyCloud&lt;/a&gt; est de pouvoir partir à n'importe
quel moment, encore faut-il pouvoir le faire facilement et savoir
comment le faire ! En attendant que l'équipe mette en place un moyen
officiel d'effectuer cette tâche, voici une méthode que j'ai utilisée
pour migrer mon instance cozy d'un serveur vers un cozy situé sur un
autre serveur distant. C'est dangereux, vous allez mettre les mains dans
le cambouis et vous salir, mais au final vous ne perdrez aucune donnée
après la migration !&lt;/p&gt;
&lt;h2 id="postscriptum"&gt;&lt;a class="toclink" href="#postscriptum"&gt;Post scriptum&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://twitter.com/nledez"&gt;Nicolas&lt;/a&gt;, de l'équipe Cozy, m'a dit qu'il
est plus rapide et plus efficace de faire une simple copie du fichier de
la base de données cozy &lt;code&gt;cozy.couch&lt;/code&gt; depuis la machine source et de le
remplacer dans la machine distante. Dans ce cas, pas besoin de vous
embêter avec toutes les péripéties de ce tutoriel ! Des gens en parlent
&lt;a href="https://forum.cozy.io/t/comment-faire-un-backup-de-la-base-de-donnees-couchdb/531"&gt;ici&lt;/a&gt;.
Si quelqu'un a plus de détails sur la méthode et confirme que celle-ci
fonctionne, je serai ravi de mettre à jour cet article, n'hésitez-pas à
me contacter ! (cf fin du message)&lt;/p&gt;
&lt;h2 id="lamthode"&gt;&lt;a class="toclink" href="#lamthode"&gt;La méthode&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Dans ce tutoriel, j'utiliserai le vocabulaire suivant :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;la machine &lt;strong&gt;source&lt;/strong&gt; sera la machine depuis laquelle on fait la
    copie du cozy. C'est elle qui contient toutes les données et que
    l'on cherche à répliquer.&lt;/li&gt;
&lt;li&gt;la machine &lt;strong&gt;cible&lt;/strong&gt; sera la machine vers laquelle on migre son
    cozy. Je recommande que cette instance dispose d'un cozy pré
    installé, &lt;strong&gt;à jour&lt;/strong&gt; (la plateforme devrait être à jour), mais sans
    aucune donnée à l'intérieur (c'est-à-dire un cozy tel qu'il serait
    juste après l'installation par les scripts). Idéalement, il faudrait
    que le nom d'utilisateur (email) de ce cozy cible soit quelque chose
    de facilement reconnaissable, vu que l'on devra identifier cet
    utilisateur plus tard... Par exemple, utiliser &lt;code&gt;demo@domain.tld&lt;/code&gt;
    comme email de login.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="cibledsactiverlascuritdesappareilsauthentifis"&gt;&lt;a class="toclink" href="#cibledsactiverlascuritdesappareilsauthentifis"&gt;Cible : Désactiver la sécurité des appareils authentifiés&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pour cette procédure, nous allons en fait nous faire passer pour
n'importe quel appareil qui voudrait se synchroniser avec le cozy,
c'est-à-dire que l'on va se faire passer pour l'application mobile
&lt;code&gt;cozy-mobile&lt;/code&gt; ou pour l'application bureau &lt;code&gt;cozy-desktop&lt;/code&gt;. Cependant, la
synchronisation avec ces appareils marche (grossièrement) de la manière
suivante :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;l'appareil qui veut se synchroniser avec le cozy s'authentifie la
    première fois, avec le mot de passe du cozy.&lt;/li&gt;
&lt;li&gt;l'appareil est inscrit dans la liste des appareils autorisés.&lt;/li&gt;
&lt;li&gt;lors des synchronisations, le serveur cozy vérifie que l'appareil
    est autorisé avant de transmettre la requête de réplication à
    couchdb, qui lui gérera l'authentification.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Seulement dans notre cas, on n'a pas la possibilité de s'inscrire en
tant qu'appareil autorisé, on va donc devoir contourner le code qui fait
cette vérification ! Bien sûr, ce ne sera que temporaire et on remettra
le code tel qu'il était à l'origine, dans la dernière étape...&lt;/p&gt;
&lt;p&gt;On se place dans le bon répertoire, tout d'abord :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd /usr/local/cozy/apps/proxy/build/server/controller/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Il faut ensuite ouvrir le fichier &lt;code&gt;devices.js&lt;/code&gt; avec les droits de
modification (je suis passé par &lt;code&gt;sudo vim devices.js&lt;/code&gt; pour le faire,
mais vous avez le droit à d'autres éditeurs de texte, inférieurs
soient-ils :D).&lt;/p&gt;
&lt;p&gt;On identifie la fonction &lt;code&gt;replication&lt;/code&gt;, et plus particulièrement la
partie qui vérifie l'authentification :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deviceManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NODE_ENV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;production&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;authorization&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getCredentialsHeader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;authorization&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getProxy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;couchdbHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;couchdbPort&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Request unauthorized&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On va juste remplacer &lt;code&gt;auth&lt;/code&gt; par &lt;code&gt;true&lt;/code&gt; dans la première condition, pour
faire croire au proxy que l'appareil est toujours authentifié :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;deviceManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isAuthenticated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=============&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ICI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;ai remplacé auth par true&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NODE_ENV&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;production&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;authorization&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getCredentialsHeader&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;authorization&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb nb-Type"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;getProxy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;couchdbHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;couchdbPort&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Request unauthorized&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On sauvegarde et on quitte, puis on relance le proxy pour être sûr que
les modifications sont prises en compte :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cozy-monitor restart proxy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="ciblercuprerlemotdepassedecouchdb"&gt;&lt;a class="toclink" href="#ciblercuprerlemotdepassedecouchdb"&gt;Cible : Récupérer le mot de passe de couchdb&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On a maintenant besoin de l'identifiant et du mot de passe pour accéder
à la base de données couchdb de la machine cible. Pour cela, il suffit
de regarder dans &lt;code&gt;/etc/cozy/couchdb.login&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cat /etc/cozy/couchdb.login
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Chez moi, ça affiche :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;bonjour
motdepasse
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;La première ligne correspond au login, la seconde au mot de passe. On
note ça quelque part, et c'est parti pour lancer la copie.&lt;/p&gt;
&lt;h2 id="sourcelancerlacopie"&gt;&lt;a class="toclink" href="#sourcelancerlacopie"&gt;Source : lancer la copie&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Depuis la machine source maintenant, on va lancer la copie. Imaginons
que ma machine cible soit située sur le nom de domaine
&lt;code&gt;cozy.example.tld&lt;/code&gt;, alors la commande à lancer est la suivante :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;backup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nl"&gt;bonjour&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;motdepasse&lt;/span&gt;&lt;span class="nv"&gt;@cozy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tld&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cozy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;où &lt;code&gt;bonjour&lt;/code&gt; et &lt;code&gt;motdepasse&lt;/code&gt; sont respectivement le nom d'utilisateur et
le mot de passe couchdb de la machine cible.&lt;/p&gt;
&lt;p&gt;La manipulation va prendre un peu de temps, et il arrive qu'elle échoue
même si vous avez beaucoup de données. Personnellement, il m'a fallu la
relancer plusieurs fois avant que ça finisse sans encombre, mais au bout
d'un moment, ça s'est arrêté de planter et ça a finalement marché.&lt;/p&gt;
&lt;h2 id="cibleremettrelauthentificationdesappareilsdanssontatinitial"&gt;&lt;a class="toclink" href="#cibleremettrelauthentificationdesappareilsdanssontatinitial"&gt;Cible : Remettre l'authentification des appareils dans son état initial&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;La sécurité étant cruciale pour éviter que n'importe qui ne puisse
récupérer vos données personnelles, pensez bien à remettre le fichier de
code modifié &lt;code&gt;devices.js&lt;/code&gt; dans son état initial (c'est-à-dire changer la
condition de &lt;code&gt;if (true)&lt;/code&gt; à &lt;code&gt;if (auth)&lt;/code&gt;), et à redémarrer le proxy sur la
machine cible :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cozy-monitor restart proxy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="ciblerafistolerlesdonnes"&gt;&lt;a class="toclink" href="#ciblerafistolerlesdonnes"&gt;Cible : Rafistoler les données&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Maintenant, on va se connecter via l'interface web à la machine cible,
comme on se connecterait à n'importe quel moment pour aller voir son
cozy. A ce point-là, je me suis connecté avec mon login et mot de passe
utilisés lors de la création du cozy cible, mais il se pourrait bien que
ça marche avec le login et mot de passe de la machine source également
(à confirmer).&lt;/p&gt;
&lt;p&gt;Le cozy cible est dans un état inconsistent. Pourquoi ?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Il y a plusieurs données qui sont censées être présentes de manière
    unique (informations sur l'instance, l'utilisateur, etc.), et qui
    sont présentes en doublons. En effet, ces données sont créées une
    fois lors de la création du cozy, et on les a en double à cause de
    la copie du cozy source. Il va falloir nettoyer ces données.&lt;/li&gt;
&lt;li&gt;Les mots de passe stockés dans la base sont chiffrés avec des clés
    qui dépendent du mot de passe de l'utilisateur et d'un sel
    cryptographique, uniques par utilisateur. Du coup, comme il y a
    plusieurs utilisateurs (rappelez-vous, les données sont en double),
    le mot de passe pourrait ne pas être déchiffré correctement, ce qui
    fait que les applications de récupération de données (comme
    &lt;a href="https://github.com/bnjbvr/kresus"&gt;kresus&lt;/a&gt; ou
    &lt;a href="https://github.com/frankrousseau/konnectors"&gt;konnectors&lt;/a&gt;) ne vont
    plus marcher correctement.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;La bonne nouvelle, c'est que ces deux problèmes se résolvent tous les
deux en supprimant les données présentes en doublons. Pour faire cela,
voici la liste des étapes :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;depuis l'interface web du cozy cible, on désinstalle l'appli
    &lt;code&gt;data browser&lt;/code&gt; (toutes mes données) si elle était présente, puis on
    la réinstalle. Cela est nécessaire parce que le cozy pourrait croire
    que l'application est installée en double (le cozy a des
    enregistrements en base de données sur les applications actuellement
    installées).&lt;/li&gt;
&lt;li&gt;on lance l'application &lt;code&gt;data-browser&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;dans la table &lt;code&gt;CozyInstance&lt;/code&gt;, on supprime l'instance qui ne
    correspond pas à celle du cozy cible (a priori, c'est celle qui n'a
    pas de nom de domaine, sauf si vous en aviez défini un sur le cozy
    cible).&lt;/li&gt;
&lt;li&gt;dans la table &lt;code&gt;StackApplication&lt;/code&gt;, on supprime toutes les lignes en
    double. Comme il s'agit des applications de la plateforme, si le
    cozy cible était bien mis à jour avant de faire ces opérations, il
    suffit de supprimer les lignes avec les numéros de version
    inférieurs ou égaux.&lt;/li&gt;
&lt;li&gt;dans la table &lt;code&gt;Applications&lt;/code&gt;, on supprime toutes les lignes (en
    cliquant sur l'icône de corbeille), &lt;strong&gt;sauf data-browser&lt;/strong&gt; qu'on a
    remis dans un état consistent à la main.&lt;/li&gt;
&lt;li&gt;dans la table &lt;code&gt;User&lt;/code&gt;, on supprime la ligne qui correspond à
    l'utilisateur du cozy cible (si vous avez suivi mon exemple, c'est
    le &lt;code&gt;demo@domain.tld&lt;/code&gt; dont je parlais au tout début).&lt;/li&gt;
&lt;li&gt;on se déconnecte et on se reconnecte sur le cozy.&lt;/li&gt;
&lt;li&gt;laisser reposer, mettre au four thermostat 6 pendant 1 minute.&lt;/li&gt;
&lt;li&gt;c'est prêt, vous pouvez déguster !&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="conclusion"&gt;&lt;a class="toclink" href="#conclusion"&gt;Conclusion&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;J'espère que cette procédure aura marché pour vous, je n'ai pas pu la
réessayer, du coup cette procédure est extraite de mes notes
personnelles et il se pourrait que j'ai oublié quelques détails. Si
c'est le cas, n'hésitez pas à me contacter sur
&lt;a href="https://twitter.com/bnjbvr"&gt;twitter&lt;/a&gt; ou sur irc (mon nick est
&lt;code&gt;bnjbvr&lt;/code&gt;). Si ça a marché et que vous avez apprécié, n'hésitez pas à me
le dire également ;-)&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Tue, 21 Apr 2015 21:12:00 +0200</pubDate><guid isPermaLink="false">tag:bouvier.cc,2015-04-21:/cozycloud-migrer-son-instance-dun-serveur-vers-un-autre/</guid><category>blog</category><category>opensource</category></item><item><title>What I've Made On Year 2014</title><link>https://bouvier.cc/what-ive-made-on-year-2014/</link><description>&lt;p&gt;I've stumbled across &lt;a href="http://isawsomecode.tumblr.com/post/106997844921/what-i-made-on-year-2014"&gt;espadrine's blog
post&lt;/a&gt;
about his accomplishments in 2014 and found it was a really good idea.
It matters a lot to acknowledge your own accomplishments, without being
overly proud about them, just to realize &lt;a href="https://en.wikipedia.org/wiki/Impostor_syndrome"&gt;you're not an
impostor&lt;/a&gt;, and that you
bring value to your company and deserve your current position (yes,
there probably will be more about the so-called impostor syndrome on
this blog).&lt;/p&gt;
&lt;h3 id="opensource"&gt;&lt;a class="toclink" href="#opensource"&gt;open-source&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;I've started &lt;a href="https://github.com/bnjbvr/kresus"&gt;kresus&lt;/a&gt;, which is
    probably my biggest personal open-source project so far. It is a
    personal finance manager, a la Linxo / Mint / Bankin, et al. The
    only difference is that you can self-host it (if you have the chance
    to own a &lt;a href="https://cozy.io"&gt;CozyCloud&lt;/a&gt; instance, which you can also
    self-host). It is a fork of another open-source project,
    &lt;a href="https://github.com/seeker89/cozy-pfm/"&gt;cozy-pfm&lt;/a&gt;, which hasn't been
    maintained for long and whose owner made a few technical choices I
    didn't personally like (using backbone was the biggest one).&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bnjbvr/minstrel"&gt;minstrel&lt;/a&gt; is a non official
    Spotify for Firefox OS app (a.k.a web app). In particular, it spawns
    a proxy server that can read your Spotify playlists, stream tracks
    in real-time, encode them in real-time before streaming them back to
    a simple HTML5 &lt;code&gt;audio&lt;/code&gt; tag. The web frontend can also synchronize
    your tracks locally, so that you can still listen to your tracks
    even when you're offline, using the awesome
    &lt;a href="http://mozilla.github.io/localForage/"&gt;localForage&lt;/a&gt; library.&lt;/li&gt;
&lt;li&gt;A few small contributions to different cozycloud projects, among
    which I'd like to highlight the &lt;a href="https://github.com/cozy/cozy-home/pull/178"&gt;app update
    notification&lt;/a&gt; in
    cozy-home ("hey, this app has a new version, go update it if you
    want to!").&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bnjbvr/diary"&gt;diary&lt;/a&gt;, a &lt;a href="https://tent.io"&gt;tent&lt;/a&gt;
    blogging application which I started earlier in 2013. I've stopped
    working on it as I don't have a lot of traction in the tent
    community.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bnjbvr/gsd"&gt;gsd&lt;/a&gt;, a todo list app started in
    December 2013, to experiment with angularjs. Stopped development as
    I found out about &lt;a href="https://github.com/jsilvestre/tasky"&gt;tasky&lt;/a&gt; and
    &lt;a href="http://bulletjournal.com/"&gt;bullet journaling&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;extended &lt;a href="https://github.com/bnjbvr/lebonsite"&gt;lebonsite&lt;/a&gt; a few by
    adding a new frontend that includes realtime search. This app works
    along with &lt;a href="https://github.com/ClementNotin/lebonscrap"&gt;lebonscrap&lt;/a&gt;
    and allows you to aggregate flat search results (it's deeply
    localized to France's flat search websites) and quickly go through
    them. Update: if you're interested in the changes I've made, they
    are in the &lt;em&gt;angular&lt;/em&gt; branch of my repository.&lt;/li&gt;
&lt;li&gt;as my job is about working in open-source, the next paragraph also
    applies here.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="schooljob"&gt;&lt;a class="toclink" href="#schooljob"&gt;school/job&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In March 2014, I've got an engineering diploma in computer science from
INSA Lyon, with the highest possible honors (in French, "félicitations
du jury"). Again, not being cocky: graduating with honors is pretty
classic and doesn't mean anything regarding your actual knowledge /
level in anything.&lt;/p&gt;
&lt;p&gt;I've been hired as a full-time employee by Mozilla at the end of
January, following my internship during Summer 2013. I work in the
Platform team, in the JavaScript Engine sub-team. My main focuses have
been extending &lt;a href="http://asmjs.org"&gt;asm.js&lt;/a&gt;, to help proving that the web
platform is ready for gaming. I mostly implemented
&lt;a href="https://github.com/johnmccutchan/ecmascript_simd"&gt;SIMD.js&lt;/a&gt; in Firefox
this year (if you're interested in reading more about this, feel free to
read the official Mozilla &lt;a href="https://blog.mozilla.org/javascript/2015/03/10/state-of-simd-js-performance-in-firefox/"&gt;blog
post&lt;/a&gt;
I've co-written).&lt;/p&gt;
&lt;h3 id="whatabout2015"&gt;&lt;a class="toclink" href="#whatabout2015"&gt;what about 2015&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I'd like to get more focused in cloud services that you own and have
control on, as I think this is the thing that matters the most,
nowadays.&lt;/p&gt;
&lt;p&gt;Also, I wish I can keep on learning new things, by myself or on massive
online open courses. As a newcomer in adulthood, I would also like to
learn how to take advantage of every single hour of every single day,
that is, not getting stuck in a routine and waking up one day thinking
"man, I'm already that old?". Oh boy, there are only 24 hours a day.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">Benjamin Bouvier</dc:creator><pubDate>Mon, 16 Mar 2015 13:22:00 +0100</pubDate><guid isPermaLink="false">tag:bouvier.cc,2015-03-16:/what-ive-made-on-year-2014/</guid><category>blog</category><category>opensource</category><category>life</category></item></channel></rss>