Phyks' bloghttp://localhost/Blog/output/2023-03-23T16:00:00+01:00I write about dev, FOSS, DIY and more, in French and English.I write about dev, FOSS, DIY and more, in French and English.pgRouting on (very) large graphs2023-03-23T16:00:00+01:002023-03-23T16:00:00+01:00Phykstag:localhost,2023-03-23:/Blog/output/2023/03/pgrouting-on-very-large-graphs.html<p>I recently performed routing and graph analysis on a very large graph built on
top of some OpenData file. The underlying graph had about 40M edges, which is
about the size of the road network mapped by OpenStreetMap in North America.
Not that much, but still a bit tricky to handle.</p>
<p>I recently performed routing and graph analysis on a very large graph built on
top of some OpenData file. The underlying graph had about 40M edges, which is
about the size of the road network mapped by OpenStreetMap in North America.
Not that much, but still a bit tricky to handle.</p>
<p>The main issue was that the source OpenData files where geometric representation
of the features (GeoJSON features, actually bunches of GeoJSON <code>Point</code> and
<code>LineString</code>), not an actual graph network. This is very different from
starting directly from OpenStreetMap data which are directly (and correctly)
noded out of th ebox: contrary to <span class="caps">OSM</span> data where <code>ways</code> are built on top of
<code>nodes</code>, so that connected ways would share a common <code>node</code> and graph
structure would come up naturally, I had a collection of <code>LineString</code> objects,
each built upon its own local set of <code>Point</code> which should be reconciled first.
See <a href="https://docs.pgrouting.org/3.1/en/pgr_nodeNetwork.html#images">this
illustration</a>
from <code>pgRouting</code> doc for an illustration of these two situations.</p>
<p>Given these constraints,</p>
<ul>
<li>The usual <span class="caps">OSM</span> routing stack (<a href="https://project-osrm.org/"><code>OSRM</code></a>,
<a href="https://www.graphhopper.com/"><code>GraphHopper</code></a>) could not be used out of
the box, apart from handling a sophisticated data transform (noding the graph).</li>
<li>The usual Python stack (<a href="https://networkx.org/"><code>networkx</code></a> and derived
libraries) could not be used (graph was too large to be stored in-memory)
and would not give meaningful routing results until the graph was
correctly noded.</li>
</ul>
<p>So, I ended up using <a href="https://pgrouting.org/"><code>pgRouting</code></a>. <code>pgRouting</code> is a
perfect match for this task:
* It has a very detailed <a href="https://docs.pgrouting.org/latest/en/">documentation</a>
* It has a ready-to-use function to <a href="https://docs.pgrouting.org/latest/en/pgr_createTopology.html">build a graph
topology</a> out
of a collection of <code>LineString</code> which is the precise transformation I needed
to be able to route on my graph.
* It comes with many ready-to-use functions to route with various algorithms,
analyze the graph (holes, connected components, etc.).</p>
<p>Given these features and its ease of use together with the usual
PostgreSQL/PostGIS/<span class="caps">GDAL</span> stack, it is very straightforward to quickly get a
minimal processing pipeline on a small subset of your graph.</p>
<h2>Minimal processing pipeline on a small subset of your graph</h2>
<p>First, import your GeoJSON features into a PostgreSQL/PostGIS database and
filter out on some bbox to have a small subset of your graph which is fine
(performance-wise) for tuning your processing pipeline:</p>
<div class="highlight"><pre><span></span><code>ogr2ogr<span class="w"> </span>-f<span class="w"> </span><span class="s2">"PostgreSQL"</span><span class="w"> </span>PG:<span class="s2">"dbname=</span><span class="nv">$PGDATABASE</span><span class="s2">"</span><span class="w"> </span>./opendata.geojson<span class="w"> </span>-explodecollections
psql<span class="w"> </span>-c<span class="w"> </span><span class="s1">'CREATE UNLOGGED TABLE opendata_partial AS SELECT * FROM opendata WHERE wkb_geometry && ST_MakeEnvelope(left,bottom,right,top, 4326);'</span>
</code></pre></div>
<p><em>Note</em>: I’m creating an <code>UNLOGGED</code> table here since I do not worry about data
consistency after a server crash and this comes with <a href="https://www.compose.com/articles/faster-performance-with-unlogged-tables-in-postgresql/">performance
improvements</a>.</p>
<p>At this point, you can easily design your pre-processing workflow on this
<code>opendata_partial</code> table. This includes:</p>
<ul>
<li>Fixing holes in data</li>
<li>Filtering out broken features/geometries</li>
<li>etc.</li>
</ul>
<p>At this point, creating your graph topology on top of your collection of
features is as simple as running
<a href="https://docs.pgrouting.org/latest/en/pgr_createTopology.html"><code>pgr_createTopology</code></a>:</p>
<div class="highlight"><pre><span></span><code><span class="err">\</span><span class="k">set</span><span class="w"> </span><span class="n">tolerance</span><span class="w"> </span><span class="mi">1</span><span class="n">e</span><span class="o">-</span><span class="mi">6</span>
<span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">opendata_partial_preprocessed</span><span class="w"> </span><span class="k">ADD</span><span class="w"> </span><span class="k">COLUMN</span><span class="w"> </span><span class="k">source</span><span class="w"> </span><span class="nb">integer</span><span class="p">;</span>
<span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">opendata_partial_preprocessed</span><span class="w"> </span><span class="k">ADD</span><span class="w"> </span><span class="k">COLUMN</span><span class="w"> </span><span class="n">target</span><span class="w"> </span><span class="nb">integer</span><span class="p">;</span>
<span class="k">SELECT</span><span class="w"> </span><span class="n">pgr_createTopology</span><span class="p">(</span>
<span class="w"> </span><span class="s1">'opendata_partial_preprocessed'</span><span class="p">,</span>
<span class="w"> </span><span class="p">:</span><span class="n">tolerance</span><span class="p">,</span>
<span class="w"> </span><span class="s1">'wkb_geometry'</span><span class="p">,</span>
<span class="w"> </span><span class="s1">'ogc_fid'</span><span class="p">,</span>
<span class="w"> </span><span class="s1">'source'</span><span class="p">,</span>
<span class="w"> </span><span class="s1">'target'</span>
<span class="p">);</span>
</code></pre></div>
<p>assuming your features lie in a <code>opendata_partial_preprocessed</code> table, with a
geometry column named <code>wkb_geometry</code>, a unique index column <code>id</code>. This call
will populate the newly created <code>source</code> and <code>target</code> columns which stores the
actual graph (each row of the table represents an edge from node id <code>source</code>
to node id <code>target</code>).</p>
<p>Topology is created up to the given <code>tolerance</code> (nodes are merged up to this
distance). Beware this is expressed in the same coordinates system as your
geometries (probably <code>EPSG:4326</code>, <code>1e-6</code> would roughly be about 10cm in France).</p>
<p>You can then <a href="https://docs.pgrouting.org/latest/en/pgr_dijkstra.html">route</a>
on this graph (directed or undirected, depending on the value you assign to
<code>reverse_cost</code>) and compute analysis on the graphs (<a href="https://docs.pgrouting.org/latest/en/pgr_analyzeGraph.html">find dead
ends</a> or
<a href="https://docs.pgrouting.org/latest/en/pgr_connectedComponents.html">extract connected
components</a>).
For example, to compute routing:</p>
<div class="highlight"><pre><span></span><code><span class="err">\</span><span class="k">set</span><span class="w"> </span><span class="n">start_lon</span><span class="w"> </span><span class="n">TODO</span>
<span class="err">\</span><span class="k">set</span><span class="w"> </span><span class="n">start_lat</span><span class="w"> </span><span class="n">TODO</span>
<span class="err">\</span><span class="k">set</span><span class="w"> </span><span class="n">end_lon</span><span class="w"> </span><span class="n">TODO</span>
<span class="err">\</span><span class="k">set</span><span class="w"> </span><span class="n">end_lat</span><span class="w"> </span><span class="n">TODO</span>
<span class="k">WITH</span>
<span class="w"> </span><span class="c1">-- Project start point on the closest point on the graph</span>
<span class="w"> </span><span class="c1">-- source is picked up in an arbitrary way here (could have been target)</span>
<span class="w"> </span><span class="k">start</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="p">(</span>
<span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="k">source</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">opendata_partial_preprocessed</span><span class="w"> </span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">wkb_geometry</span><span class="w"> </span><span class="o"><-></span><span class="w"> </span><span class="n">ST_SetSRID</span><span class="p">(</span><span class="w"> </span><span class="n">ST_GeomFromText</span><span class="p">(</span><span class="s1">'POINT ('</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">:</span><span class="s1">'start_lon'</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="s1">' '</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">:</span><span class="s1">'start_lat'</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="s1">')'</span><span class="p">),</span><span class="w"> </span><span class="mi">4326</span><span class="p">)</span><span class="w"> </span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">1</span>
<span class="w"> </span><span class="p">),</span>
<span class="w"> </span><span class="c1">-- Project destination point on the closest point on the graph</span>
<span class="w"> </span><span class="n">destination</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="p">(</span>
<span class="w"> </span><span class="k">SELECT</span><span class="w"> </span><span class="k">source</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">opendata_partial_preprocessed</span><span class="w"> </span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="n">wkb_geometry</span><span class="w"> </span><span class="o"><-></span><span class="w"> </span><span class="n">ST_SetSRID</span><span class="p">(</span><span class="w"> </span><span class="n">ST_GeomFromText</span><span class="p">(</span><span class="s1">'POINT ('</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">:</span><span class="s1">'end_lon'</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="s1">' '</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="p">:</span><span class="s1">'end_lat'</span><span class="w"> </span><span class="o">||</span><span class="w"> </span><span class="s1">')'</span><span class="p">),</span><span class="w"> </span><span class="mi">4326</span><span class="p">)</span><span class="w"> </span><span class="k">LIMIT</span><span class="w"> </span><span class="mi">1</span>
<span class="w"> </span><span class="p">)</span>
<span class="c1">-- Route with Dijkstra and merge with the edges table (opendata_partial_preprocessed) to get the geometries for each step of the route</span>
<span class="k">SELECT</span>
<span class="w"> </span><span class="n">id</span><span class="p">,</span>
<span class="w"> </span><span class="n">pt</span><span class="p">.</span><span class="n">wkb_geometry</span>
<span class="k">FROM</span><span class="w"> </span><span class="n">pgr_dijkstra</span><span class="p">(</span>
<span class="w"> </span><span class="s1">'SELECT id, source, target, ST_Length(wkb_geometry::geography) AS cost FROM opendata_partial_preprocessed'</span><span class="p">,</span>
<span class="w"> </span><span class="nb">array</span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="k">source</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="k">start</span><span class="p">),</span>
<span class="w"> </span><span class="nb">array</span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="k">source</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">destination</span><span class="p">),</span>
<span class="w"> </span><span class="n">directed</span><span class="w"> </span><span class="p">:</span><span class="o">=</span><span class="w"> </span><span class="k">false</span>
<span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">di</span>
<span class="k">JOIN</span><span class="w"> </span><span class="n">opendata_partial_preprocessed</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">pt</span>
<span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">di</span><span class="p">.</span><span class="n">edge</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pt</span><span class="p">.</span><span class="n">id</span><span class="p">;</span>
</code></pre></div>
<h2>Going towards processing your entire graph</h2>
<p>First, running the same pipeline will likely
<a href="https://gis.stackexchange.com/questions/337636/pgr-createtopology-uses-too-much-memory-and-connection-to-the-server-has-been-l">fail</a>
on a very large graph. The <a href="https://gis.stackexchange.com/a/337642">solution</a>
is to make partial/incremental calls to <code>pgr_createTopology</code>.</p>
<p>Then, computing Dijkstra on such a large graph will be really slow since the
<span class="caps">SQL</span> query in the previous section would recompute all costs on the fly.
Instead, you can precompute all costs once and for all to speed up any
subsequent routing queries:</p>
<div class="highlight"><pre><span></span><code><span class="k">ALTER</span><span class="w"> </span><span class="k">TABLE</span><span class="w"> </span><span class="n">opendata</span><span class="w"> </span><span class="k">ADD</span><span class="w"> </span><span class="k">COLUMN</span><span class="w"> </span><span class="k">IF</span><span class="w"> </span><span class="k">NOT</span><span class="w"> </span><span class="k">EXISTS</span><span class="w"> </span><span class="ss">"cost"</span><span class="w"> </span><span class="nb">float</span><span class="p">;</span>
<span class="k">UPDATE</span><span class="w"> </span><span class="n">opendata</span><span class="w"> </span><span class="k">SET</span><span class="w"> </span><span class="n">cost</span><span class="o">=</span><span class="n">ST_Length</span><span class="p">(</span><span class="n">wkb_geometry</span><span class="p">::</span><span class="n">geography</span><span class="p">);</span>
</code></pre></div>
<p>And then use this new column in calls to Dijkstra:</p>
<div class="highlight"><pre><span></span><code><span class="k">SELECT</span>
<span class="w"> </span><span class="n">id</span><span class="p">,</span>
<span class="w"> </span><span class="n">pt</span><span class="p">.</span><span class="n">wkb_geometry</span>
<span class="k">FROM</span><span class="w"> </span><span class="n">pgr_dijkstra</span><span class="p">(</span>
<span class="w"> </span><span class="s1">'SELECT id, source, target, cost AS cost, cost AS reverse_cost FROM opendata_partial_preprocessed'</span><span class="p">,</span>
<span class="w"> </span><span class="nb">array</span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="k">source</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="k">start</span><span class="p">),</span>
<span class="w"> </span><span class="nb">array</span><span class="p">(</span><span class="k">SELECT</span><span class="w"> </span><span class="k">source</span><span class="w"> </span><span class="k">FROM</span><span class="w"> </span><span class="n">destination</span><span class="p">),</span>
<span class="w"> </span><span class="n">directed</span><span class="w"> </span><span class="p">:</span><span class="o">=</span><span class="w"> </span><span class="k">false</span>
<span class="p">)</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">di</span>
<span class="k">JOIN</span><span class="w"> </span><span class="n">opendata_partial_preprocessed</span><span class="w"> </span><span class="k">AS</span><span class="w"> </span><span class="n">pt</span>
<span class="w"> </span><span class="k">ON</span><span class="w"> </span><span class="n">di</span><span class="p">.</span><span class="n">edge</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">pt</span><span class="p">.</span><span class="n">id</span><span class="p">;</span>
</code></pre></div>
<h2>Techniques to efficiently process the whole graph</h2>
<p>Here are a few additional tips for processing very large graphs:</p>
<ul>
<li>
<p>Topology creation can sometimes be further optimized by replacing
<code>pgr_createTopology</code> by <code>pgr_extractVertices</code>. An example for creating a
routing topology using <code>pgr_extractVertices</code> is provided in <a href="https://docs.pgrouting.org/3.5/en/pgr_extractVertices.html#create-a-routing-topology">pgRouting
doc</a>.</p>
</li>
<li>
<p>Whenever you want to run extra computation on the whole graph
(<code>pgr_connectedComponents</code> for instance), you might run into memory
errors. This is because PostgreSQL has some hard limits on how large a
data structure might be (about <span class="caps">1GB</span>) and you might end up having transient
data structures larger than this. A quick workaround is to run tiled
or grid computations by superimposing a grid on your network. An example
for <code>pgr_connectedComponents</code> is provided in <a href="https://lists.osgeo.org/pipermail/pgrouting-users/2023-January/002530.html">this pgrouting-users <span class="caps">ML</span>
thread</a>.</p>
</li>
</ul>Parallel GPG decryption2023-01-14T12:00:00+01:002023-01-14T12:00:00+01:00Phykstag:localhost,2023-01-14:/Blog/output/2023/01/parallel-gpg-decryption.html<p>I recently had to decrypt about 500k asymetrically <span class="caps">GPG</span>-encrypted
strings and found out that it can take quite a lot of time while not being as
straightforward as one might think to process in a concurrent manner to
accelerate the computation time. Here is a quick work around for <span class="caps">GPG</span>
parallel decryption.</p>
<p>I recently had to decrypt about 500k asymetrically <span class="caps">GPG</span>-encrypted
strings and found out that it can take quite a lot of time while not being as
straightforward as one might think to process in a concurrent manner to
accelerate the computation time. Here is a quick work around for <span class="caps">GPG</span>
parallel decryption.</p>
<p>I was initially using
<a href="https://gnupg.readthedocs.io/en/latest/"><code>python-gnupg</code></a> in a simple Python
<code>for</code> loop:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">gc</span>
<span class="kn">import</span> <span class="nn">getpass</span>
<span class="kn">import</span> <span class="nn">logging</span>
<span class="kn">import</span> <span class="nn">shutil</span>
<span class="kn">import</span> <span class="nn">tempfile</span>
<span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
<span class="kn">import</span> <span class="nn">gnupg</span>
<span class="k">def</span> <span class="nf">_decrypt_text</span><span class="p">(</span><span class="n">encrypted_text</span><span class="p">,</span> <span class="n">gpg</span><span class="p">):</span>
<span class="n">decrypted</span> <span class="o">=</span> <span class="n">gpg</span><span class="o">.</span><span class="n">decrypt</span><span class="p">(</span><span class="n">encrypted_text</span><span class="p">)</span>
<span class="k">assert</span> <span class="n">decrypted</span><span class="o">.</span><span class="n">ok</span><span class="p">,</span> <span class="s1">'Unable to decrypt!'</span>
<span class="k">return</span> <span class="n">decrypted</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">decode</span><span class="p">()</span>
<span class="n">private_key_path</span> <span class="o">=</span> <span class="s1">'...'</span> <span class="c1"># Path to the exported private key to use</span>
<span class="n">encrypted_texts</span> <span class="o">=</span> <span class="p">[</span><span class="o">...</span><span class="p">]</span> <span class="c1"># List of encrypted texts to decrypt</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">gnupghome</span> <span class="o">=</span> <span class="n">tempfile</span><span class="o">.</span><span class="n">mkdtemp</span><span class="p">()</span>
<span class="n">gpg</span> <span class="o">=</span> <span class="n">gnupg</span><span class="o">.</span><span class="n">GPG</span><span class="p">(</span><span class="n">gnupghome</span><span class="o">=</span><span class="n">gnupghome</span><span class="p">)</span>
<span class="n">private_key_path</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">Path</span><span class="p">(</span><span class="n">private_key_path</span><span class="p">)</span><span class="o">.</span><span class="n">expanduser</span><span class="p">())</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'Importing private key from </span><span class="si">%s</span><span class="s1">...'</span><span class="p">,</span> <span class="n">private_key_path</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">private_key_path</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">fh</span><span class="p">:</span>
<span class="n">private_key</span> <span class="o">=</span> <span class="n">gpg</span><span class="o">.</span><span class="n">decrypt_file</span><span class="p">(</span><span class="n">fh</span><span class="p">,</span> <span class="n">passphrase</span><span class="o">=</span><span class="n">getpass</span><span class="o">.</span><span class="n">getpass</span><span class="p">(</span><span class="s1">'Private key passphrase?'</span><span class="p">))</span>
<span class="k">assert</span> <span class="n">private_key</span><span class="o">.</span><span class="n">ok</span><span class="p">,</span> <span class="s1">'Unable to decrypt private key with provided passphrase!'</span>
<span class="n">import_key</span> <span class="o">=</span> <span class="n">gpg</span><span class="o">.</span><span class="n">import_keys</span><span class="p">(</span><span class="n">private_key</span><span class="o">.</span><span class="n">data</span><span class="p">)</span>
<span class="k">assert</span> <span class="n">import_key</span><span class="o">.</span><span class="n">count</span> <span class="o">></span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'No private key could be imported!'</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'The following </span><span class="si">%s</span><span class="s1"> keys where successfully imported: </span><span class="si">%s</span><span class="s1">'</span><span class="p">,</span> <span class="n">import_key</span><span class="o">.</span><span class="n">count</span><span class="p">,</span> <span class="s1">','</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">import_key</span><span class="o">.</span><span class="n">fingerprints</span><span class="p">)))</span>
<span class="n">decrypted_texts</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">_decrypt_text</span><span class="p">(</span><span class="n">encrypted_text</span><span class="p">,</span> <span class="n">gpg</span><span class="p">)</span> <span class="k">for</span> <span class="n">encrypted_text</span> <span class="ow">in</span> <span class="n">encrypted_texts</span>
<span class="p">]</span>
<span class="k">finally</span><span class="p">:</span>
<span class="n">shutil</span><span class="o">.</span><span class="n">rmtree</span><span class="p">(</span><span class="n">tmp_gnupghome</span><span class="p">)</span>
<span class="n">gc</span><span class="o">.</span><span class="n">collect</span><span class="p">()</span>
</code></pre></div>
<p>This was taking a substantial amount of time and (obviously) running on a
single <span class="caps">CPU</span> core. Extrapolating from the run time to process 1k records (3
seconds), it would take an approximate of 25 hours.</p>
<p>So, I thought about using as much <span class="caps">CPU</span> cores as possible, but parallel
processing turned out not to be as simple as a wrapping of my <code>for</code> loop with
<a href="https://joblib.readthedocs.io/en/latest/"><code>joblib</code></a>.</p>
<p>This is because <span class="caps">GPG</span>, since version 2, relies heavily on <code>gpg-agent</code> which is a
single process and acts as a bottleneck here. I’m not very familiar with the
<span class="caps">GPG</span> code base but there are a couple of issues around on this topic (<a href="https://dev.gnupg.org/T2813">this
one</a> for instance).</p>
<p>A quick work around is to run multiple <code>gpg-agent</code> in parallel. This is easily
achieved in practice since <span class="caps">GPG</span> creates one <code>gpg-agent</code> process per
<code>GNUPGHOME</code>. So, I could simply initialize a pool of <code>GPG</code> instances and
rotate among them for parallel processing:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">gc</span>
<span class="kn">import</span> <span class="nn">getpass</span>
<span class="kn">import</span> <span class="nn">logging</span>
<span class="kn">import</span> <span class="nn">shutil</span>
<span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span>
<span class="kn">import</span> <span class="nn">gnupg</span>
<span class="kn">from</span> <span class="nn">joblib</span> <span class="kn">import</span> <span class="n">Parallel</span><span class="p">,</span> <span class="n">delayed</span>
<span class="n">private_key_path</span> <span class="o">=</span> <span class="s1">'...'</span> <span class="c1"># Path to the exported private key to use</span>
<span class="n">encrypted_texts</span> <span class="o">=</span> <span class="p">[</span><span class="o">...</span><span class="p">]</span> <span class="c1"># List of encrypted texts to decrypt</span>
<span class="n">n_jobs</span> <span class="o">=</span> <span class="mi">100</span> <span class="c1"># Needs to be tuned to your machine specs</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">gpg</span> <span class="o">=</span> <span class="n">gnupg</span><span class="o">.</span><span class="n">GPG</span><span class="p">()</span>
<span class="n">private_key_path</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">Path</span><span class="p">(</span><span class="n">private_key_path</span><span class="p">)</span><span class="o">.</span><span class="n">expanduser</span><span class="p">())</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">private_key_path</span><span class="p">,</span> <span class="s1">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">fh</span><span class="p">:</span>
<span class="n">private_key</span> <span class="o">=</span> <span class="n">gpg</span><span class="o">.</span><span class="n">decrypt_file</span><span class="p">(</span><span class="n">fh</span><span class="p">,</span> <span class="n">passphrase</span><span class="o">=</span><span class="n">getpass</span><span class="o">.</span><span class="n">getpass</span><span class="p">(</span><span class="s1">'Private key passphrase?'</span><span class="p">))</span>
<span class="k">assert</span> <span class="n">private_key</span><span class="o">.</span><span class="n">ok</span><span class="p">,</span> <span class="s1">'Unable to decrypt private key with provided passphrase!'</span>
<span class="n">gpg_workers_list</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">n_jobs</span><span class="p">):</span>
<span class="n">tmp_gnupghome</span> <span class="o">=</span> <span class="n">tempfile</span><span class="o">.</span><span class="n">mkdtemp</span><span class="p">()</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'Using temporary GNUPGHOME </span><span class="si">%s</span><span class="s1">...'</span><span class="p">,</span> <span class="n">tmp_gnupghome</span><span class="p">)</span>
<span class="n">gpg</span> <span class="o">=</span> <span class="n">gnupg</span><span class="o">.</span><span class="n">GPG</span><span class="p">(</span><span class="n">gnupghome</span><span class="o">=</span><span class="n">tmp_gnupghome</span><span class="p">)</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'Importing private key from </span><span class="si">%s</span><span class="s1">...'</span><span class="p">,</span> <span class="n">private_key_path</span><span class="p">)</span>
<span class="n">import_key</span> <span class="o">=</span> <span class="n">gpg</span><span class="o">.</span><span class="n">import_keys</span><span class="p">(</span><span class="n">private_key</span><span class="o">.</span><span class="n">data</span><span class="p">)</span>
<span class="k">assert</span> <span class="n">import_key</span><span class="o">.</span><span class="n">count</span> <span class="o">></span> <span class="mi">0</span><span class="p">,</span> <span class="s1">'No private key could be imported!'</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s1">'The following </span><span class="si">%s</span><span class="s1"> keys where successfully imported: </span><span class="si">%s</span><span class="s1">'</span><span class="p">,</span> <span class="n">import_key</span><span class="o">.</span><span class="n">count</span><span class="p">,</span> <span class="s1">','</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">import_key</span><span class="o">.</span><span class="n">fingerprints</span><span class="p">)))</span>
<span class="n">gpg_workers_list</span><span class="p">[</span><span class="n">tmp_gnupghome</span><span class="p">]</span> <span class="o">=</span> <span class="n">gpg</span>
<span class="n">decrypted_texts</span> <span class="o">=</span> <span class="n">Parallel</span><span class="p">(</span><span class="n">n_jobs</span><span class="o">=</span><span class="n">n_jobs</span><span class="p">)(</span>
<span class="n">delayed</span><span class="p">(</span><span class="n">_decrypt_text</span><span class="p">)(</span>
<span class="n">encrypted_text</span><span class="p">,</span>
<span class="nb">list</span><span class="p">(</span><span class="n">gpg_workers_list</span><span class="o">.</span><span class="n">values</span><span class="p">())[</span><span class="n">i</span> <span class="o">%</span> <span class="n">n_jobs</span><span class="p">]</span>
<span class="p">)</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">encrypted_text</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">encrypted_texts</span><span class="p">)</span>
<span class="p">)</span>
<span class="k">finally</span><span class="p">:</span>
<span class="k">for</span> <span class="n">tmp_gnupghome</span> <span class="ow">in</span> <span class="n">gpg_workers_list</span><span class="o">.</span><span class="n">keys</span><span class="p">():</span>
<span class="n">shutil</span><span class="o">.</span><span class="n">rmtree</span><span class="p">(</span><span class="n">tmp_gnupghome</span><span class="p">)</span>
<span class="n">gc</span><span class="o">.</span><span class="n">collect</span><span class="p">()</span>
</code></pre></div>
<p>With this workaround, I was able to process the full 500k records in less than
15 minutes.</p>
<p><em>Note:</em> The goal of this snippet is to demonstrate how to quickly get parallel
decryption of <span class="caps">GPG</span>-encrypted texts. Much can be done to handle passphrases and
secrets in a more secure manner, but this is beyond the scope of this article.</p>Tp-Link Tapo C210 camera without internet2021-12-07T23:00:00+01:002021-12-07T23:00:00+01:00Phykstag:localhost,2021-12-07:/Blog/output/2021/12/tp-link-tapo-c210-camera-without-internet.html<p>It is quite challenging today to find a “security camera” (<span class="caps">IP</span> camera) which
offers cloudless features, decent price and standard <span class="caps">RTSP</span> feeds. The only one
I could come across is the Tp-Link Tapo C210 with this setup.</p>
<p>It is quite challenging today to find a “security camera” (<span class="caps">IP</span> camera) which
offers cloudless features, decent price and standard <span class="caps">RTSP</span> feeds. The only one
I could come across is the Tp-Link Tapo C210 with this setup.</p>
<p>Tp-Link Tapo C210 camera is a cheap security camera, having 360 degrees
rotation (which in my case is useful to physically ensure the camera is not
filming when set to confidentiality mode) and exposing a basic <span class="caps">API</span> on the
local network which can be used in Python script.</p>
<h2>Installation</h2>
<p>It can be configured in a cloud-less (without internet connection) environment
with the following steps:</p>
<ul>
<li>Install the “Tp-Link Tapo” app on your smartphone and create a cloud
account. This is counterintuitive for this scenario, but required. We will
never use an internet connection from now on.</li>
<li>Switch your smartphone to airplane mode and install the camera as usual
(connect your smartphone to the camera wifi, set up the real wifi to use).
The real wifi to use does not need to have access to Internet (it is fully
firewalled in my case).</li>
<li>Connect to your firewalled wifi, camera should be working locally through
the app.</li>
</ul>
<p>From this point, you can use the “Tp-Link Tapo” app to control your camera on
your local network.</p>
<p><strong>Note:</strong> The app <strong>does not</strong> work when using a <span class="caps">VPN</span> interface to connect remotely
(typically your mobile phone on <span class="caps">LTE</span> network + Wireguard link). You can however
control the Tapo camera over such a link through <span class="caps">RTSP</span> feed and the next sections.</p>
<h2>Controlling <span class="caps">PTZ</span> (Pan/Tilt/Zoom) and switching privacy mode programmatically</h2>
<p>Provided you are fluent with scripting, you can also discard completely the
“Tp-Link Tapo” app from now on:</p>
<ul>
<li>The camera can expose standards <a href="https://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol"><span class="caps">RTSP</span>
feeds</a> (which
<span class="caps">VLC</span> supports for instance). You just need to set up a local camera account
by going to “Advanced settings” > “Camera Account” in the “Tp-Link
Tapo” app. You can then connect to <code>rtsp://<YOUR_TAPO_IP>/stream1</code> in <span class="caps">VLC</span>
and provide these credentials.</li>
<li>The camera itself can be fully controlled outside of the app through its
<span class="caps">API</span>. In Python, <a href="https://github.com/JurajNyiri/pytapo"><code>pytapo</code></a> library
will help you a lot. You need to provide it the <span class="caps">IP</span> of your Tapo camera,
<code>admin</code> as username and your Tp-Link cloud password as password. Although
we do provide it our cloud credentials, everything works fully locally in
this setup (no internet access required, neither from the script nor from
the camera).</li>
</ul>
<p>Out of the box, the Tapo C210 camera does not have a physical protection when
confidentiality mode is on. With a bit of scripting, you can leverage its
ability to rotate 360 degrees to make it turn against a wall when
confidentiality mode is set:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">pytapo</span>
<span class="n">MAX_ITERATIONS</span><span class="o">=</span><span class="mi">25</span>
<span class="k">def</span> <span class="nf">get_privacy_mode</span><span class="p">(</span><span class="n">tapo</span><span class="p">):</span>
<span class="k">return</span> <span class="n">tapo</span><span class="o">.</span><span class="n">getPrivacyMode</span><span class="p">()</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">'enabled'</span><span class="p">,</span> <span class="s1">'off'</span><span class="p">)</span> <span class="o">==</span> <span class="s1">'on'</span>
<span class="k">def</span> <span class="nf">toggle_privacy</span><span class="p">(</span><span class="n">tapo</span><span class="p">):</span>
<span class="n">current_privacy</span> <span class="o">=</span> <span class="n">get_privacy_mode</span><span class="p">(</span><span class="n">tapo</span><span class="p">)</span>
<span class="c1"># Note: moving is disabled when in privacy mode.</span>
<span class="k">if</span> <span class="n">current_privacy</span><span class="p">:</span>
<span class="n">tapo</span><span class="o">.</span><span class="n">setPrivacyMode</span><span class="p">(</span><span class="kc">False</span><span class="p">)</span>
<span class="c1"># Wait for privacy mode to be off, while avoiding infinite loop is the camera is stuck for some reason.</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">MAX_ITERATIONS</span><span class="p">):</span>
<span class="n">current_privacy</span> <span class="o">=</span> <span class="n">get_privacy_mode</span><span class="p">(</span><span class="n">tapo</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">current_privacy</span><span class="p">:</span>
<span class="k">break</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.2</span><span class="p">)</span>
<span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s1">'Tapo stuck in privacy mode!'</span><span class="p">)</span>
<span class="n">tapo</span><span class="o">.</span><span class="n">moveMotor</span><span class="p">(</span><span class="o">-</span><span class="mi">180</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">tapo</span><span class="o">.</span><span class="n">moveMotor</span><span class="p">(</span><span class="mi">180</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
<span class="n">tapo</span><span class="o">.</span><span class="n">setPrivacyMode</span><span class="p">(</span><span class="kc">True</span><span class="p">)</span>
</code></pre></div>
<h2>Ensuring correct date/time without <span class="caps">NTP</span></h2>
<p>As the Tapo C210 does not have internet access, it cannot rely on <span class="caps">NTP</span> to get
correct date and time. Fortunately, setting up date / time manually can be
easily done through the <a href="https://github.com/FalkTannhaeuser/python-onvif-zeep"><span class="caps">ONVIF</span> interface</a>:</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">onvif</span> <span class="kn">import</span> <span class="n">ONVIFCamera</span>
<span class="n">mycam</span> <span class="o">=</span> <span class="n">ONVIFCamera</span><span class="p">(</span><span class="s1">'<YOUR_TAPO_IP>'</span><span class="p">,</span> <span class="mi">2020</span><span class="p">,</span> <span class="s1">'<YOUR_TAPO_USERNAME>'</span><span class="p">,</span> <span class="s1">'<YOUR_TAPO_PASSWORD>'</span><span class="p">,</span> <span class="s1">'/etc/onvif/wsdl/'</span><span class="p">)</span>
<span class="n">time_params</span> <span class="o">=</span> <span class="n">mycam</span><span class="o">.</span><span class="n">devicemgmt</span><span class="o">.</span><span class="n">create_type</span><span class="p">(</span><span class="s1">'SetSystemDateAndTime'</span><span class="p">)</span>
<span class="n">time_params</span><span class="o">.</span><span class="n">DateTimeType</span> <span class="o">=</span> <span class="s1">'Manual'</span>
<span class="n">time_params</span><span class="o">.</span><span class="n">DaylightSavings</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">time_params</span><span class="o">.</span><span class="n">TimeZone</span> <span class="o">=</span> <span class="s1">'GMT+01:00'</span> <span class="c1"># Edit according to your timezone</span>
<span class="n">time_params</span><span class="o">.</span><span class="n">UTCDateTime</span> <span class="o">=</span> <span class="n">mycam</span><span class="o">.</span><span class="n">devicemgmt</span><span class="o">.</span><span class="n">GetSystemDateAndTime</span><span class="p">()</span><span class="o">.</span><span class="n">UTCDateTime</span>
<span class="c1"># Adjust UTCDateTime if required</span>
<span class="c1"># time_params.UTCDateTime.Date.{Day,Month,Year} = ...</span>
<span class="c1"># time_params.UTCDateTime.Time.{Hour,Minute,Second} = ...</span>
<span class="n">mycam</span><span class="o">.</span><span class="n">devicemgmt</span><span class="o">.</span><span class="n">SetSystemDateAndTime</span><span class="p">(</span><span class="n">time_params</span><span class="p">)</span>
</code></pre></div>
<p>where <code><YOUR_TAPO_USERNAME></code>/<code><YOUR_TAPO_PASSWORD></code> are the credentials for
the local account set up in the Tapo app (not the <code>admin</code> / Tp-Link cloud credentials!).</p>
<h2>Left to explore</h2>
<ul>
<li>[ ] Motion detection, either through Tapo itself or through Motion/<span class="caps">ML</span>/ZoneMinder</li>
<li>[ ] Position presets</li>
<li>[ ] Local rolling archive with a Raspberry Pi</li>
</ul>Audio / video quality of streaming services2021-02-14T17:00:00+01:002021-02-14T17:00:00+01:00Phykstag:localhost,2021-02-14:/Blog/output/2021/02/audio-video-quality-of-streaming-services.html<p>This is a quick reminder for myself about ways to check the audio / video
quality of streaming services.</p>
<p>This is a quick reminder for myself about ways to check the audio / video
quality of streaming services.</p>
<h2>Netflix</h2>
<p>Netflix offers 1080p with Dolby Digital+ 5.1 sound (without the 4k option) or
4k / Dolby Atmos with the 4k option.</p>
<p>Current streaming quality (resolution and bitrate + audio format) can be checked through the debug console:</p>
<ul>
<li>On a computer (including website), it can be opened through
<code>Ctrl + Alt + Shift + D</code> (on an Azerty keyboard);</li>
<li>On an Android <span class="caps">TV</span>, it can be opened with <code>F4</code> / <code>F8</code> (this requires an <span class="caps">USB</span> or
Bluetooth keyboard).</li>
</ul>
<p>On my computer and Firefox, I needed <a href="https://addons.mozilla.org/fr/firefox/addon/netflix-1080p-firefox/">this
extension</a>
to force it to 1080p.</p>
<h2>MyCanal</h2>
<p>MyCanal offers 1080p with 2.0 sound. Some contents should be in
4K and Dolby Digital 5.1 but 1) only <a href="https://assistance.canalplus.com/questions/2223516-mycanal-android-android-tv-chromecast-infos-qualite-image-1080p-4k">a limited set of
devices</a>
are supported at the moment and 2) it is only for the “live” content and <a href="https://assistance.canalplus.com/questions/2211389-probleme-5-1-home-cinema-decodeur-canal-4k">not
for replay</a>.</p>
<p>To check the current formats and bitrates, you can use:</p>
<ul>
<li>On a computer (website), right click on the video and “Informations de
débogage”. You can open the <span class="caps">URL</span> under “<span class="caps">CDN</span> Location” in a new tab and
compare the downloading bitrate with the ones listed in the manifest;</li>
<li>On an Android <span class="caps">TV</span>, you can click 4 or 5 times on the version number in the
settings (a “Tchi Tcha” sound should ring). Then, you can enable the debug
window which displays the full details about audio/video bitrate and formats.</li>
</ul>
<p>Note that in order to get 1080p / 4k, you will need <a href="https://assistance.canalplus.com/questions/2223516-mycanal-android-android-tv-chromecast-infos-qualite-image-1080p-4k">a “Widevine L1”
device</a>.</p>
<p>The situation is evolving quite rapidly and is quite dependent between live
and replay (“à la demande”) programs. <a href="https://assistance.canalplus.com/questions/2223516-mycanal-android-android-tv-chromecast-infos-qualite-image-1080p-4k">This
page</a>
and the comments below are the most up to date source of information.</p>
<h2><span class="caps">DVB</span>-T (French “<span class="caps">TNT</span>”)</h2>
<p><span class="caps">TNT</span> is only 1080p with Dolby Digital 2.0 sound. Apparently, <a href="https://forum.telesatellite.com/showthread.php/1989-R%C3%A9ponse-de-France-2-concernant-la-supression-du-son-DD-5.1">no channels are
emitting with higher resolution or better audio
quality</a>,
even on Internet streaming.</p>
<p><a href="https://www.digitalbitrate.com/?lang=fr">DigitalBitrate</a> is a useful resource
to check the details of <span class="caps">TV</span> channels on <span class="caps">TNT</span> / <span class="caps">IPTV</span> / MyCanal.</p>
<h2>Amazon Prime</h2>
<p>Sadly, I am not aware of any means to check the Amazon Prime video quality, be
it on computer or Android <span class="caps">TV</span>.</p>
<h2>Disney+</h2>
<p>Disney+ should have <a href="https://jloh.co/notes/disney-debug-menu/">a debug menu</a>
showing details about stream quality, accessible through <code>Ctrl + Shift + .</code>.</p>
<p>This does not seem to work on Android <span class="caps">TV</span>.</p>Android 10 without Google services (replacement with microg) on an LG G6 (H870)2020-11-22T14:30:00+01:002020-11-22T14:30:00+01:00Phykstag:localhost,2020-11-22:/Blog/output/2020/11/android-10-without-google-services-replacement-with-microg-on-an-lg-g6-h870.html<p>This article is a quick summary of the steps I used to get a working
<a href="http://lineageos.org/">Lineage</a> + <a href="https://microg.org/">microg</a> setup on my
European <span class="caps">LG</span> G6 (h870), acting as a reminder for me and hoping it can help
others. I voluntarily give little details since I expect the reader to be
already familiar with Android alternative ROMs and flashing them.</p>
<p>This article is a quick summary of the steps I used to get a working
<a href="http://lineageos.org/">Lineage</a> + <a href="https://microg.org/">microg</a> setup on my
European <span class="caps">LG</span> G6 (h870), acting as a reminder for me and hoping it can help
others. I voluntarily give little details since I expect the reader to be
already familiar with Android alternative ROMs and flashing them.</p>
<h2>Installation steps</h2>
<ol>
<li>First, you should <a href="https://forum.xda-developers.com/lg-g6/how-to/official-lg-g6-bootloader-unlock-t3614719">unlock your
bootloader</a>.</li>
<li>(Windows required for this step) Then, you should update to the latest official firmware (v30b) using <a href="https://www.lg.com/us/support/help-library/lg-bridge-download-how-to-use-CT10000026-1438110404543"><span class="caps">LG</span>
Bridge</a>.
Pro-tip: to make sure the upgrade process works smoothly, go into “Download
Mode” (phone powered off, press volume up and connect <span class="caps">USB</span> cable). Make sure
you do <strong>all</strong> the available official upgrades.</li>
<li>Then, you can install a custom recovery. You should install
<a href="https://sourceforge.net/projects/pa-g6/files/Releases/SHRP/"><span class="caps">SHRP</span></a> which
is maintained and Android 10 compatible. Otherwise, the only working
version of <span class="caps">TWRP</span> I could find for the <span class="caps">LG</span> G6 is the
<a href="https://dl.twrp.me/h870/twrp-3.3.0-0-h870.img.html">3.3.0-0</a> version. This
however is not fully compatible with Android 10 and has issues with the
<code>/data</code> partition (it works perfectly fine for Lineage 15.1 / 16.0
though!). Other versions would result in boot loops (recovery boot loops
or, worse, boot logo boot loops) or be unable to mount the system partition
(red error message “Failed to mount /system (device or resource busy)”).</li>
<li>Then, format data, reboot and go to “Wipe” > “Advanced wipe” and select
“cache Dalvik / <span class="caps">ART</span>”, “cache”, “data” et “system”). Be advised that
checking “system” here will wipe your existing operating system on your
device, I used it here to be sure to make a clean flash of the Lineage <span class="caps">ROM</span>.
Reboot in recovery afterwards.</li>
<li>Then, <code>adb push</code> the <a href="https://forum.xda-developers.com/t/rom-a10-h870-h870ds-h872-us997-lineageos-17-1-for-lg-g6-unofficial.4137809/">Lineage 17.1
<span class="caps">ROM</span></a>
and install it through <span class="caps">TWRP</span>.</li>
<li>Flash
<a href="https://www.xda-developers.com/how-to-install-magisk/">Magisk</a>
to get root abilities (this is now the standard way of having root, see
<a href="https://www.xda-developers.com/lineageos-dropping-superuser-addonsu-implementation-favor-magisk-manager/">https://www.xda-developers.com/lineageos-dropping-superuser-addonsu-implementation-favor-magisk-manager/</a>.
Also flash
[https://f-droid.org/fr/packages/org.fdroid.fdroid.privileged.ota/] if you
want F-Droid to be able to automatically update your apps.</li>
<li>Reboot the normal system and go through the initial configuration wizard.</li>
<li>Install <a href="https://f-droid.org/F-Droid.apk">F-Droid</a>.</li>
<li>Install <a href="https://github.com/Nanolx/NanoDroid#downloads">NanoDroid patcher</a>,
following the deodexing procedure in <a href="https://github.com/Nanolx/NanoDroid/blob/master/doc/DeodexServices.md#vdex">their
wiki</a>
(I had both the vdex and odex file, but following vdex instructions were
enough) and flashing the <code>NanoDroid-patcher-*.zip</code> file through recovery
(this one takes quite a few minutes, this is normal).</li>
<li>Use a <a href="https://f-droid.org/fr/packages/com.google.zxing.client.android/">barcode
scanner</a>
to scan the <a href="https://microg.org/download.html">microg F-Droid repo QRCode</a>
and install “Services Core” (GmsCore), “Services Framework Proxy” and “Fake
Store” through F-Droid. Also install “DroidGuard Helper” if you need to
pass <a href="https://developer.android.com/training/safetynet">SafetyNet</a>. Note
that on Android 7 or later, GmsCore has to be installed as a system app,
see <a href="https://github.com/microg/GmsCore/wiki/Installation">microG wiki</a>.</li>
<li>Install a network geolocation backend, such as “Apple UnifiedNip” (or any
other of your preference).</li>
<li>Start the “GmsCore” app and run the autotest (checking signature spoofing
is enabled, permissions are granted, etc.).</li>
<li>You might be interested in
<a href="https://f-droid.org/en/packages/net.typeblog.shelter/">Shelter</a> from
F-Droid if you plan on installing non-opensource apps.</li>
<li>If you want to download APKs from the Play Store, you can install <a href="https://f-droid.org/fr/packages/com.aurora.store/">Aurora
Store</a> from F-Droid.</li>
</ol>
<h2>Tips</h2>
<ul>
<li>I got stuck once in a boot logo boot loop (device would reboot
automatically, never going further than the <span class="caps">LG</span> boot logo). This is very
annoying and I did not find any way to do a hard power-off of this device.
Since the battery is not removable, it seems the only option is to let the
device run out of battery.</li>
<li>I got stuck in a reboot recovery loop sometimes, although I did have a
system (<span class="caps">ROM</span>) installed on the device. The device would never boot into the
<span class="caps">OS</span>. <a href="https://forum.xda-developers.com/showpost.php?p=74982559&postcount=3">This
post</a>
did the trick: powering off the device, going into normal recovery (power +
volume down until <span class="caps">LG</span> logo, then release power and push it again) and
picking “yes” twice would get you into recovery and fix the boot loop.</li>
<li>I got stuck once in the <span class="caps">LG</span> <a href="https://www.reddit.com/r/lgg6/comments/bi9ovl/i_have_an_lg_g6_that_stuck_on_the_firmware_update/">“Firmware
update”</a>
mode, with the device waiting for a firmware on <span class="caps">USB</span> and no possibility to
exit. You can exit this mode by pressing simultaneously volume up +
volume down + power for a few seconds.</li>
<li><a href="https://github.com/Nanolx/NanoDroid">NanoDroid</a> promises to give an easy
way to install the full microg suite. It is however bloated with features
you do not necessarily want (see <a href="https://github.com/nift4/microg_installer_revived#doesnt-nanodroid-fix-the-problem">this
comment</a>).</li>
<li><a href="https://f-droid.org/fr/packages/de.robv.android.xposed.installer/">XPosed Installer</a>
is an alternative option, letting you install the XPosed Framework and use
the <a href="https://repo.xposed.info/module/com.thermatk.android.xf.fakegapps">“Fake
GApps”</a>
XPosed module for signature spoofing. This however requires adding the
whole XPosed framework, which seems unmaintained and latest version source
code is not published. It seems XPosed has been superseded by
<a href="https://forum.xda-developers.com/xposed/development/official-edxposed-successor-xposed-t4070199">EdXPosed</a>.</li>
<li>If you want to flash Lineage 15.1 or Lineage 16.0, you might end up with a
message such as</li>
</ul>
<div class="highlight"><pre><span></span><code>Comparing TZ versions:
Max TZ version: TZ.BF.4.0.1.C4-126433
Current TZ version: TZ.BF.4.0.1-143200
</code></pre></div>
<p>and an error due to a failed assertion. This is because your bootloader is
too high version, and you should flash a Nougat bootloader (downgrade).</p>
<ul>
<li>If you want to dump the official <span class="caps">KDZ</span> images, copy the files appearing in
<code>C:\Users\YourUsername\AppData\Local\LG Electronics\LG Bridge\SWUpgrade\Image</code> somewhere safe. These files are automatically
purged after a successful upgrade!</li>
<li>Special boot modes of the <span class="caps">LG</span> G6 are described <a href="https://wiki.lineageos.org/devices/h870">in the Lineage wiki</a>.</li>
<li>If you want to go back to Stock mode, simply start the device in Download
Mode and use the official “<span class="caps">LG</span> Bridge” tool to perform update / reinitialization.</li>
</ul>Des données ouvertes citoyennes ?2019-10-03T18:00:00+02:002019-10-03T18:00:00+02:00Phykstag:localhost,2019-10-03:/Blog/output/2019/10/des-donnees-ouvertes-citoyennes.html<p>La ville de <a href="http://www.ville-montrouge.fr/">Montrouge</a>, au Sud de Paris, ne
fournit aucune donnée ouverte (aussi appelées “opendata”) et ce malgré les
<a href="https://www.lagazettedescommunes.com/586475/open-data-et-collectivites-qui-fait-quoi-et-comment/">obligations
légales</a>
pour les collectivités de cette taille. La situation n’évolue malheureusement
pas, avec plusieurs refus et prises de position contre la publication de
telles données par la ville. Qu’à cela ne tienne, un groupe de contributeurs
d’<a href="https://www.openstreetmap.org/">OpenStreetMap</a> s’est organisé sur la
commune et a décidé de collecter et diffuser lui-même de telles données
ouvertes !</p>
<p>La ville de <a href="http://www.ville-montrouge.fr/">Montrouge</a>, au Sud de Paris, ne
fournit aucune donnée ouverte (aussi appelées “opendata”) et ce malgré les
<a href="https://www.lagazettedescommunes.com/586475/open-data-et-collectivites-qui-fait-quoi-et-comment/">obligations
légales</a>
pour les collectivités de cette taille. La situation n’évolue malheureusement
pas, avec plusieurs refus et prises de position contre la publication de
telles données par la ville. Qu’à cela ne tienne, un groupe de contributeurs
d’<a href="https://www.openstreetmap.org/">OpenStreetMap</a> s’est organisé sur la
commune et a décidé de collecter et diffuser lui-même de telles données
ouvertes !</p>
<p>L’organisation de la contribution à Montrouge, à travers le groupe
<a href="https://twitter.com/osmontrouge">OSMontrouge</a>, a permis d’organiser et
motiver la contribution par thématique. Des positions exactes des adresses sur
les entrées des bâtiments au recensement des stationnements deux-roues en
passant par le relevé des différents parcmètres de la ville et de leur zone de
tarification (entre autres), la base <span class="caps">OSM</span> à Montrouge est probablement
désormais la base de référence sur la ville pour bon nombre de sujets.</p>
<p>Depuis le 1er octobre, OSMontrouge
<a href="https://twitter.com/osmontrouge/status/1179067010686312449">“libère”</a> un jeu
de données par jour. L’expression peut paraître surprenante pour des données
qui sont déjà, de fait, sous <a href="https://www.openstreetmap.org/copyright/fr">licence
ODbL</a> car présente dans la base
<span class="caps">OSM</span>. Tout l’enjeu est en réalité ici de réaliser des extractions thématiques
et de publier les jeux de données résultants, en clin d’œil aux données
ouvertes traditionnellement publiées par les administrations et collectivités.</p>
<p>C’est en effet toute la spécificité et l’originalité de cette démarche, unique
à ma connaissance. Quand d’habitude une administration collecte ses données,
puis les publie sous licence ouverte afin qu’elles puissent enrichir d’autres
projets (citoyens ou non) tels qu’une intégration à OpenStreetMap, la
situation est ici complètement renversée. Les citoyens collectent eux-mêmes la
donnée sur le terrain et l’ajoute dans OpenStreetMap. Ils fournissent alors
des jeux de “données ouvertes” sur un <a href="https://data.osmontrouge.fr/explore/?sort=modified">portail similaire à ce qu’utilisent
habituellement les
administrations</a>, dans une
sorte de défi lancé à celles-ci de réutiliser leurs données !</p>
<p>Enfin, la conversion des citoyens en producteurs de données à part entière
s’accompagne de pratiques différentes sûrement liées à leurs expériences de
réutilisateurs. Exit la frustration ressentie face à des données souvent
incomplètes, dépassées ou inutilisables faute de documentation, la
documentation est ici aussi exhaustive que possible (sans compter l’ample
documentation du <a href="https://wiki.openstreetmap.org/">wiki OpenStreetMap</a>), toute
la pile logicielle est libre, les données sont mises à jour quotidiennement et
la contribution et les corrections sont facilitées (un simple compte
OpenStreetMap suffit).</p>
<p>Et si, finalement, les données ne pouvaient être vraiment ouvertes que
lorsqu’elles sont conçues dès le début comme un commun ?</p>Bicycle routing avoiding road works2019-07-16T14:00:00+02:002019-07-16T14:00:00+02:00Phykstag:localhost,2019-07-16:/Blog/output/2019/07/bicycle-routing-avoiding-road-works.html<p>Many cities (and administrative areas) in France are providing <a href="https://framagit.org/phyks/cygnal/blob/master/scripts/opendata/works.py#L491-583">OpenData
feeds</a>
concerning ongoing road works. All are not as detailed or as precise, but they
all provide the information about potential traffic disruption in this area.</p>
<p>When you ride a bicycle, most road work may actually affect your route, either
directly (bicycle lane closed without any deviation) or indirectly (road works
usually means a lot of traffic jam, and it may be tricky even with a bicycle).
Can we have a router avoiding road works?</p>
<p>Many cities (and administrative areas) in France are providing <a href="https://framagit.org/phyks/cygnal/blob/master/scripts/opendata/works.py#L491-583">OpenData
feeds</a>
concerning ongoing road works. All are not as detailed or as precise, but they
all provide the information about potential traffic disruption in this area.</p>
<p>When you ride a bicycle, most road work may actually affect your route, either
directly (bicycle lane closed without any deviation) or indirectly (road works
usually means a lot of traffic jam, and it may be tricky even with a bicycle).
Can we have a router avoiding road works?</p>
<p><a href="https://github.com/abrensch/brouter">BRouter</a> is a very nice, efficient and
customizable router (which can run either on your <a href="https://f-droid.org/fr/packages/btools.routingapp/">Android
phone</a> or with a <a href="http://brouter.de/brouter-web/">web
interface</a>). It has a feature to exclude some
areas from the routing algorithm (called “nogo areas”). These areas were
initially circles but it was recently extended to support polylines and
polygons exclusion areas.</p>
<p>Conversely, <a href="http://brouter.de/brouter-web/">Brouter-web</a> got recently
extended to support the import of such nogo features from a GeoJSON file (such
as <a href="https://opendata.paris.fr/explore/dataset/chantiers-perturbants/download/?format=geojson&timezone=Europe/Berlin">the one provided by Paris city
hall</a>).
By default, the importing nogo areas are totally excluded (as can be seen with
the weight <code>-1</code> set in the import modal).</p>
<p>Then, one can compute a route, and these road works area will be excluded from
the calculation, leading to longer (but safer!) routes!</p>
<p>Here is an example, where the typical route (best compromise) would normally
be given by the first image. It takes the “Rue Didot”, which sadly is affected
by road works. When taking them into account (pink areas on the second image),
a detour is proposed, along the rails, resulting in a longer but safer route
(full exclusion of road works is used here).</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2019/07/routing_without_road_works.png">
<img
style="max-width: 45%; min-width: 400px; max-height: 600px"
src="http://localhost/Blog/output/images/2019/07/routing_without_road_works.png"
alt="When not taking into account road works, the best route uses Rue
Didot." />
</a>
<a href="http://localhost/Blog/output/images/2019/07/routing_road_works.png">
<img
style="max-width: 45%; min-width: 400px; max-height: 600px"
src="http://localhost/Blog/output/images/2019/07/routing_road_works.png"
alt="Due to road works, Rue Didot is no longer usable. An alternative
route is computed." />
</a>
</p>
<p>To refine the route further, one can filter the OpenData GeoJSON file on the
starting date or impact of the road works, to only include the road works
affecting the highway and currently going on. I recently added to BRouter
support for not only full exclusion areas but penalty areas.</p>
<p>Changing the <code>- 1</code> cost (full exclusion) to a positive cost value, the area
can be crossed but with a penalty given by the cost times the distance
travelled across the area. This way, one might try to avoid a square with road
works, while still considering it in case the alternative route is too long.</p>
<p>Providing your city has an OpenData feed for road works, routing and taking
them into account is now possible!</p>Voyager en train + vélo en France2019-07-12T14:00:00+02:002019-07-12T14:00:00+02:00Phykstag:localhost,2019-07-12:/Blog/output/2019/07/voyager-en-train-velo-en-france.html<p>Voici une liste de gares par ordre alphabétique avec les astuces que je
connais pour entrer / sortir ou changer de quai en restant au maximum à niveau.</p>
<p>Si vous ne trouvez pas la gare que vous cherchez, une bonne piste est en
général de regarder sur <a href="https://www.openstreetmap.org/">OpenStreetMap</a> qui a
en …</p><p>Voici une liste de gares par ordre alphabétique avec les astuces que je
connais pour entrer / sortir ou changer de quai en restant au maximum à niveau.</p>
<p>Si vous ne trouvez pas la gare que vous cherchez, une bonne piste est en
général de regarder sur <a href="https://www.openstreetmap.org/">OpenStreetMap</a> qui a
en général un très bon rendu de ces infrastructures, avec les éventuels
numéros de voie et les passages souterrains / ascenseurs.</p>
<p>Concernant les trains, vous pouvez également voir :</p>
<ul>
<li><a href="https://fr.wikipedia.org/wiki/Transport_des_v%C3%A9los_en_train#Agencement_des_mat%C3%A9riels_et_des_gares">https://fr.wikipedia.org/wiki/Transport_des_v%C3%A9los_en_train#Agencement_des_mat%C3%A9riels_et_des_gares</a>,</li>
<li><a href="https://www.francevelotourisme.com/conseils/velo-et-transports/voyager-en-train-avec-son-velo">https://www.francevelotourisme.com/conseils/velo-et-transports/voyager-en-train-avec-son-velo</a>,</li>
<li><a href="https://droitauvelo.org/Emporter-son-velo-dans-le-train-3">https://droitauvelo.org/Emporter-son-velo-dans-le-train-3</a> (pour le Nord de
la France)</li>
</ul>
<h3><a href="https://www.openstreetmap.org/node/3467086693#map=16/48.4340/0.0986">Gare d’Alençon</a></h3>
<p>À l’exception de la voie 1, accès aux voies par la passerelle (ascenseurs
standards, peu profonds, ou escaliers).</p>
<h3><a href="https://www.openstreetmap.org/node/3549779824#map=16/48.3421/2.3790">Gare de Boigneville</a></h3>
<p>Changement de quai par un passage à niveau piéton.</p>
<h3><a href="https://www.openstreetmap.org/node/5598384401">Gare de Caen</a></h3>
<p>Correspondances et sortie par passage souterrain obligatoires. Ascenseurs
disponibles sur chaque quais.</p>
<h3><a href="https://www.openstreetmap.org/node/384941569#map=16/48.4484/1.4809">Gare de Chartres</a></h3>
<p>Au printemps 2019, gare en travaux. Sortie par des escaliers sans rampes ni rigole.</p>
<h3><a href="https://www.openstreetmap.org/way/112095036">Gare de Cherbourg</a></h3>
<p>Gare de terminus, tous les quais sont à niveau avec la rue.</p>
<h3><a href="https://www.openstreetmap.org/node/2480463408#map=16/45.7789/3.1006">Gare de Clermont-Ferrand</a></h3>
<p>Correspondances et sorties par un souterrain (escaliers et ascenseurs).</p>
<h3><a href="https://www.openstreetmap.org/way/135520937">Gare de Granville</a></h3>
<p>Gare de terminus, correspondances à niveau.</p>
<h3><a href="https://www.openstreetmap.org/way/392773608">Gare d’Orléans</a></h3>
<p>Gare de terminus, tout est accessible à niveau.</p>
<h3><a href="https://www.openstreetmap.org/way/180207327">Gare de Lamotte-Beuvron</a></h3>
<p>Deux voies, correspondance par passage souterrain. Ramples d’accès <span class="caps">PMR</span>
complètes pour accéder à toutes les parties de la gare.</p>
<h3><a href="https://www.openstreetmap.org/node/3419908160">Gare de Paris Austerlitz</a></h3>
<p>Gare à niveau de la rue, accès direct sans marche.</p>
<h3><a href="https://www.openstreetmap.org/node/1823210835">Gare de Paris Bercy</a></h3>
<p>Accès aux trains à niveau par la rampe des taxis et le dépose-minute.</p>
<h3><a href="https://www.openstreetmap.org/node/26824135">Gare de Paris Lyon</a></h3>
<p>Accès direct au Hall 2 (et aux autres halls ensuite) possible par la <a href="https://www.openstreetmap.org/way/190665705#map=18/48.84390/2.37915">rampe au
bout de la Rue de
Rambouillet</a>.</p>
<h3><a href="https://www.openstreetmap.org/node/65331500">Gare de Paris Montparnasse</a></h3>
<p>Accès possible aux quais par les ascenseurs (pas très profonds) dans le hall
du côté de la tour Montparnasse.</p>
<p>Accès possible avec une rampe en suivant le <a href="https://www.openstreetmap.org/way/409799416">parking
dépose-minute</a> (entrée de la
rampe sur le Boulevard de Vaugirard).</p>
<p>Pour les trains au départ de la gare de Montparnasse - Vaugirard, accès par
une rampe possible par la rue André Gide et le <a href="https://www.openstreetmap.org/way/156544410">parking
dépose-minute</a>.</p>
<p>Stationnement longue-durée (vélo) possible sur les arceaux du parking du
dépose-minute Pasteur. Stationnement vélo dans les parkings payants.</p>
<h3><a href="https://www.openstreetmap.org/node/3533789791">Gare de Paris Saint-Lazare</a></h3>
<p>Accès directement au niveau des quais (Ile-de-France et Normandie) par
l’entrée au bout de l’<a href="https://www.openstreetmap.org/way/190288615#map=19/48.87704/2.32713">Impasse
d’Amsterdam</a>,
côté Rue d’Amsterdam.</p>
<h3><a href="https://www.openstreetmap.org/node/818899103#map=16/48.2934/2.4012">Gare de Malesherbes</a></h3>
<p>Accès au quai soit directement, soit par un passage à niveau piéton.</p>
<h3><a href="https://www.openstreetmap.org/node/4975045143#map=16/46.3193/-0.4543">Gare de Niort</a></h3>
<p>Correspondances et changements de quai par un passage souterrain, sans
équipement spécifique (escaliers simples), à l’été 2018.</p>
<h3><a href="https://www.openstreetmap.org/way/96736633">Gare de Pontorson</a></h3>
<p>Correspondances et changement de quais par un passage à niveau piéton.
Attention, pas de guichets et seulement une borne <span class="caps">TER</span> présente en gare.</p>
<h3><a href="https://www.openstreetmap.org/way/72956506">Gare de Royan</a></h3>
<p>Gare de terminus, tout est accessible à niveau.</p>
<h3><a href="https://www.openstreetmap.org/node/368276184">Gare de Saintes</a></h3>
<p>Voie 6 accessible directement depuis la rue (à travers le hall de la gare).
Les autres voies sont accessibles par un passage souterrain uniquement
(escaliers uniquement, pas de rampes ni d’ascenseurs).</p>
<h3><a href="https://www.openstreetmap.org/node/2351574817">Gare de Surdon</a></h3>
<p>Gare avec un seul quai (et deux voies). Sorties par un passage à niveau
piéton, pour traverser les voies.</p>
<h3><a href="https://www.openstreetmap.org/node/26744333">Gare de Toulon</a></h3>
<p>Accès direct à niveau depuis la rue pour la voie A. Voies B, C, D et E
accessibles par passage souterrain (escaliers ou escalators uniquement).</p>Tiling BruitParif data with QGIS2019-06-29T16:00:00+02:002019-06-29T16:00:00+02:00Phykstag:localhost,2019-06-29:/Blog/output/2019/06/tiling-bruitparif-data-with-qgis.html<p><a href="http://bruitparif.fr/">BruitParif</a>, the organism in charge of evaluating
noise pollution in Paris area, publishes <a href="https://carto.bruitparif.fr/">a map</a>
with measured noise levels in Paris. This map is however not reusable easily
elsewhere, but they offer to download it as opendata shape files (<span class="caps">SHP</span> files).
Let us see how to quickly export raster tiles to use with
<a href="https://leafletjs.com/">Leaflet</a> from these shape files and
<a href="https://qgis.org/fr/site/"><span class="caps">QGIS</span></a>.</p>
<p><a href="http://bruitparif.fr/">BruitParif</a>, the organism in charge of evaluating
noise pollution in Paris area, publishes <a href="https://carto.bruitparif.fr/">a map</a>
with measured noise levels in Paris. This map is however not reusable easily
elsewhere, but they offer to download it as opendata shape files (<span class="caps">SHP</span> files).
Let us see how to quickly export raster tiles to use with
<a href="https://leafletjs.com/">Leaflet</a> from these shape files and
<a href="https://qgis.org/fr/site/"><span class="caps">QGIS</span></a>.</p>
<p>Let us start from their opendata <a href="https://www.bruitparif.fr/carto/isophones/Vue%20globale/E3-agglos/A_Route_Lden_Agglo.zip">shape
file</a>.
After unzipping it, we can load it in <span class="caps">QGIS</span>, adding a new vector source and
following <a href="https://docs.qgis.org/2.8/en/docs/user_manual/working_with_vector/supported_data.html">this
doc</a>.
This will load all the vector data in <span class="caps">QGIS</span>.</p>
<p>Now, let us quickly reproduce the <code>carto.bruitparif.fr</code> style, going to the
layer style properties and adding styles based on the columns data (noise
level). My <span class="caps">QGIS</span> project is available at
<a href="https://tiles.phyks.me/bruitparif/bruitparif.qgz">https://tiles.phyks.me/bruitparif/bruitparif.qgz</a>.</p>
<p>Then, to generate tiles, one can use the “Tiles <span class="caps">XYZ</span>” extension available in
from within the extensions manager. In the “Processing toolbox” (Ctrl + Alt +
T), a new entry “Generate <span class="caps">XYZ</span> tiles” will appear under “TilesXYZ”. You can
then customize the extents, zoom levels etc to generate tiles for. Note that
tiles generation can be really long.</p>
<p>In the end, you get a folder with all the generated tiles, which you can copy
to a webserver and reuse.</p>
<p>For BruitParif noise data for car traffic, I generated tiles between <code>Z=0</code> and
<code>Z=18</code> which are available at
<code>https://tiles.phyks.me/bruitparif/{z}/{x}/{y}.png</code> and can be reused anywhere
afterwards, such as in <a href="http://brouter.de/brouter-web/">BRouter-web</a>. When
generating your own tiles, you can also customize transparency to use these
tiles for overlay. The total tiles between <code>Z=0</code> and <code>Z=18</code> weights around
<span class="caps">6GB</span>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2019/06/bruitparif-brouter.png">
<img
style="max-width: 800px; max-height: 600px"
src="http://localhost/Blog/output/images/2019/06/bruitparif-brouter.png"
alt="BruitParif data within Brouter-web" />
</a>
</p>Cycl’Assist/Cygnal 0.4 is out!2019-01-22T23:50:00+01:002019-01-22T23:50:00+01:00Phykstag:localhost,2019-01-22:/Blog/output/2019/01/cyclassistcygnal-04-is-out.html<p><a href="https://framagit.org/phyks/cygnal">Cycl’Assist</a> aims to be a webapp
to ease tracking and reporting issues with bike infrastructures while riding
your bike (any danger on the way such as holes in the ground, cars parked like
sh*t, road work, etc). You can think of it as Waze for bikes :) Version 0 …</p><p><a href="https://framagit.org/phyks/cygnal">Cycl’Assist</a> aims to be a webapp
to ease tracking and reporting issues with bike infrastructures while riding
your bike (any danger on the way such as holes in the ground, cars parked like
sh*t, road work, etc). You can think of it as Waze for bikes :) Version 0.4 is
now out and live at <a href="https://cygnal.eu/">https://cygnal.eu/</a>! Here is
a list of the main new features.</p>
<h2>New name and dedicated domain (cygnal.eu)</h2>
<p>Starting from this version, Cycl’Assist (formerly) is renamed Cygnal (from
“cycle” and “signal”). The code is still available on
<a href="https://framagit.org/phyks/cygnal">Framagit</a>.</p>
<p>The previous addresses will still be working but the app is now hosted at
<a href="https://app.cygnal.eu/#/">https://app.cygnal.eu/#/</a>. The sandbox version for
testing purposes is now available at
<a href="https://dev.cygnal.eu/#/">https://dev.cygnal.eu/#/</a>. There is now a new
landing page at <a href="https://cygnal.eu/">https://cygnal.eu/</a>.</p>
<h2>Better OpenData import process</h2>
<p>This version reworks the way OpenData are imported. Roadworks areas will now
be imported when the information is available from the OpenData source, in
order to show the real impact of the roadworks on the map.</p>
<p>Roadworks from <a href="http://www.hauts-de-seine.fr/">Hauts-de-Seine</a> are now imported.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2019/01/cygnal_roadworks.png">
<img
style="max-width: 800px; max-height: 600px"
src="http://localhost/Blog/output/images/2019/01/cygnal_roadworks.png"
alt="Now importing the areas for the roadworks" />
</a>
</p>
<h2>Search feature</h2>
<p>Cygnal now lets you search for a specific location. The map will be centered
around this location, while showing reports around. This will let you more
easily browse known reports and issues, without disclosing your precise geolocation.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2019/01/cygnal_search.png">
<img
style="max-width: 800px; max-height: 600px"
src="http://localhost/Blog/output/images/2019/01/cygnal_search.png"
alt="New search feature for Cygnal" />
</a>
</p>
<h2>Service worker</h2>
<p>Cygnal now has a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API">service
worker</a>.
This provides an easy way to cache assets locally and ensure a better
experience on mobile devices.</p>
<p>Up to date browsers should now offer you to install Cygnal as an application
on your mobile devices. This is the case with
<a href="https://developer.mozilla.org/en-US/docs/Web/Apps/Progressive/Add_to_home_screen">Firefox</a>
and
<a href="https://1.bp.blogspot.com/-pNa6RsY00_k/WJR_7fC8cSI/AAAAAAAAeCU/A3Jlc5Qk0fgcZcnFiVRsGpdtQKtvl15xQCLcB/s1600/google-web-app-1.jpg.gif">Chrome</a>.</p>
<p>This new features also introduce a new settings to cache map tiles (map
background images). If you regularly bike on the same route, you can now
customize the caching options of the map tiles, to reduce your network usage
on your commute.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2019/01/cygnal_caching.png">
<img
style="max-width: 800px; max-height: 600px"
src="http://localhost/Blog/output/images/2019/01/cygnal_caching.png"
alt="Permanent notification of Cycl'Assist" />
</a>
</p>Liste de données et documents disponibles sur Montrouge2019-01-22T19:00:00+01:002019-01-22T19:00:00+01:00Phykstag:localhost,2019-01-22:/Blog/output/2019/01/liste-de-donnees-et-documents-disponibles-sur-montrouge.html<p>La ville de <a href="https://fr.wikipedia.org/wiki/Montrouge">Montrouge</a> n’a
malheureusement aucune donnée ouverte disponible. J’ai donc commencé <a href="https://pub.phyks.me/Montrouge/">une
page</a> pour lister toutes les données
d’intérêt pour le territoire de Montrouge que j’ai pu recenser jusqu’à présent.</p>
<p>La ville de <a href="https://fr.wikipedia.org/wiki/Montrouge">Montrouge</a> n’a
malheureusement aucune donnée ouverte disponible. J’ai donc commencé <a href="https://pub.phyks.me/Montrouge/">une
page</a> pour lister toutes les données
d’intérêt pour le territoire de Montrouge que j’ai pu recenser jusqu’à présent.</p>
<p>Les données et documents disponibles pour l’instant sont :</p>
<ul>
<li>
<p>des copies des compte rendus des séances des <a href="https://pub.phyks.me/Montrouge/Conseils%20Municipaux/">Conseils
Municipaux</a> et des
<a href="https://pub.phyks.me/Montrouge/Comites%20de%20quartier/">Comités de
Quartier</a>. Ce sont
des copies des documents disponibles sur <a href="http://ville-montrouge.fr/">le site de la
ville</a>.</p>
</li>
<li>
<p>la <a href="https://pub.phyks.me/Montrouge/Conseils%20Municipaux/Analyse/">liste des
élus</a>, les
commissions dont ils sont membres et les informations de participation aux
conseils municipaux, librement réutilisables. Ce jeu de données à été
constitué à la main à partir des compte rendus des conseils municipaux.</p>
</li>
<li>
<p>quelques informations intéressantes, repérées dans les documents
disponibles, tel que <a href="https://pub.phyks.me/Montrouge/Conseils%20Municipaux/2018/Annexes-du-Conseil-municipal-du-22-mars-2018.pdf">les tarifs du stationnement en
2018</a>
dans une annexe de compte rendu de conseil municipal.</p>
</li>
</ul>
<p>Montrouge a également une <a href="https://wiki.openstreetmap.org/wiki/Montrouge">page sur le wiki
d’OpenStreetMap</a> très active et
recensant les données intégrées à OpenStreetMap. Il est ainsi possible d’avoir
facilement la <a href="https://wiki.openstreetmap.org/wiki/Montrouge#Parcm.C3.A8tres">liste des
parcmètres</a> de
la ville ou encore <a href="https://wiki.openstreetmap.org/wiki/Montrouge#Stationnements_deux_roues">les stationnements
vélos</a>
référencés sur le territoire de la ville.</p>Manage expiration of cached assets with Service Worker caching2019-01-05T16:00:00+01:002019-01-05T16:00:00+01:00Phykstag:localhost,2019-01-05:/Blog/output/2019/01/manage-expiration-of-cached-assets-with-service-worker-caching.html<p>My <a href="https://framagit.org/phyks/cygnal">Cygnal</a> app uses
<a href="http://openstreetmap.org/"><span class="caps">OSM</span></a> map tiles to render the map on which the
reports are shown. It is meant to be used in realtime, on your mobile phone,
mounted on your bike and there can often be some network issues in this setup.</p>
<p>I was looking for a way …</p><p>My <a href="https://framagit.org/phyks/cygnal">Cygnal</a> app uses
<a href="http://openstreetmap.org/"><span class="caps">OSM</span></a> map tiles to render the map on which the
reports are shown. It is meant to be used in realtime, on your mobile phone,
mounted on your bike and there can often be some network issues in this setup.</p>
<p>I was looking for a way to cache the map tiles locally, so that if the tile
has already been used recently, the mobile phone would not download it once
again (then sparing some network bandwidth and displaying the map even with
network issues).</p>
<p>The most basic option is to rely on the <span class="caps">HTTP</span> headers for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching">cache
control</a>. Sadly,
these are set by the server and the client side has no easy control on them
and the caching strategy. Additionally, the browser may not serve the cached
file if the server end is not reachable (in case of network issue).</p>
<p>Another approach is to have a look at <a href="https://developer.mozilla.org/fr/docs/Web/API/Service_Worker_API/Using_Service_Workers">Service
Workers</a>
which have a <a href="https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker#using_the_cache_api">Caching
<span class="caps">API</span></a>.
This is the way I decided to use and I will now detail it. I will not cover
the basics of Service Workers and Caching <span class="caps">API</span>, which are already well covered
on the web, but instead describe my particular setup to cache responses and
control cache expiration.</p>
<p>The main issue we have to face with the Caching <span class="caps">API</span> is that caching is done
indefinitely and it is the app’s role to delete expired items from the cache.
Additionally, there seems to be no way of accessing the date at which an
entry was put in the cache, so we have to find a trick to keep this info.</p>
<p>Here is my <code>fetch</code> handler in my <code>sw.js</code> Service Worker file:</p>
<div class="highlight"><pre><span></span><code><span class="c1">// Name of the cache</span>
<span class="kd">const</span><span class="w"> </span><span class="nx">CACHE_NAME</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"cache"</span><span class="p">;</span>
<span class="c1">// Caching duration of the items, one week here</span>
<span class="kd">const</span><span class="w"> </span><span class="nx">CACHING_DURATION</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mf">7</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">24</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">3600</span><span class="p">;</span>
<span class="c1">// Verbose logging or not</span>
<span class="kd">const</span><span class="w"> </span><span class="nx">DEBUG</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">true</span><span class="p">;</span>
<span class="nb">global</span><span class="p">.</span><span class="nx">self</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">'fetch'</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="nx">event</span><span class="p">)</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">request</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">event</span><span class="p">;</span>
<span class="w"> </span><span class="c1">// ...</span>
<span class="w"> </span><span class="nx">event</span><span class="p">.</span><span class="nx">respondWith</span><span class="p">(</span><span class="nb">global</span><span class="p">.</span><span class="nx">caches</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="sb">`</span><span class="si">${</span><span class="nx">CACHE_NAME</span><span class="si">}</span><span class="sb">-tiles`</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span>
<span class="w"> </span><span class="nx">cache</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">cache</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">request</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span>
<span class="w"> </span><span class="p">(</span><span class="nx">response</span><span class="p">)</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// If there is a match from the cache</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">response</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">DEBUG</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`SW: serving </span><span class="si">${</span><span class="nx">request</span><span class="p">.</span><span class="nx">url</span><span class="si">}</span><span class="sb"> from cache.`</span><span class="p">);</span>
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">expirationDate</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Date</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">response</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'sw-cache-expires'</span><span class="p">));</span>
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">now</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">();</span>
<span class="w"> </span><span class="c1">// Check it is not already expired and return from the</span>
<span class="w"> </span><span class="c1">// cache</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">expirationDate</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="nx">now</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">response</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="c1">// Otherwise, let's fetch it from the network</span>
<span class="w"> </span><span class="nx">DEBUG</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`SW: no match in cache for </span><span class="si">${</span><span class="nx">request</span><span class="p">.</span><span class="nx">url</span><span class="si">}</span><span class="sb">, using network.`</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// Note: We HAVE to use fetch(request.url) here to ensure we</span>
<span class="w"> </span><span class="c1">// have a CORS-compliant request. Otherwise, we could get back</span>
<span class="w"> </span><span class="c1">// an opaque response which we cannot inspect</span>
<span class="w"> </span><span class="c1">// (https://developer.mozilla.org/en-US/docs/Web/API/Response/type).</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">fetch</span><span class="p">(</span><span class="nx">request</span><span class="p">.</span><span class="nx">url</span><span class="p">).</span><span class="nx">then</span><span class="p">((</span><span class="nx">liveResponse</span><span class="p">)</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Compute expires date from caching duration</span>
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">expires</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">();</span>
<span class="w"> </span><span class="nx">expires</span><span class="p">.</span><span class="nx">setSeconds</span><span class="p">(</span>
<span class="w"> </span><span class="nx">expires</span><span class="p">.</span><span class="nx">getSeconds</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">CACHING_DURATION</span><span class="p">,</span>
<span class="w"> </span><span class="p">);</span>
<span class="w"> </span><span class="c1">// Recreate a Response object from scratch to put</span>
<span class="w"> </span><span class="c1">// it in the cache, with the extra header for</span>
<span class="w"> </span><span class="c1">// managing cache expiration.</span>
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">cachedResponseFields</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">status</span><span class="o">:</span><span class="w"> </span><span class="nx">liveResponse</span><span class="p">.</span><span class="nx">status</span><span class="p">,</span>
<span class="w"> </span><span class="nx">statusText</span><span class="o">:</span><span class="w"> </span><span class="nx">liveResponse</span><span class="p">.</span><span class="nx">statusText</span><span class="p">,</span>
<span class="w"> </span><span class="nx">headers</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="s1">'SW-Cache-Expires'</span><span class="o">:</span><span class="w"> </span><span class="nx">expires</span><span class="p">.</span><span class="nx">toUTCString</span><span class="p">()</span><span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">};</span>
<span class="w"> </span><span class="nx">liveResponse</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">forEach</span><span class="p">((</span><span class="nx">v</span><span class="p">,</span><span class="w"> </span><span class="nx">k</span><span class="p">)</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">cachedResponseFields</span><span class="p">.</span><span class="nx">headers</span><span class="p">[</span><span class="nx">k</span><span class="p">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">v</span><span class="p">;</span>
<span class="w"> </span><span class="p">});</span>
<span class="w"> </span><span class="c1">// We will consume body of the live response, so</span>
<span class="w"> </span><span class="c1">// clone it before to be able to return it</span>
<span class="w"> </span><span class="c1">// afterwards.</span>
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">returnedResponse</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">liveResponse</span><span class="p">.</span><span class="nx">clone</span><span class="p">();</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">liveResponse</span><span class="p">.</span><span class="nx">blob</span><span class="p">().</span><span class="nx">then</span><span class="p">((</span><span class="nx">body</span><span class="p">)</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">DEBUG</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span>
<span class="w"> </span><span class="sb">`SW: caching tiles </span><span class="si">${</span><span class="nx">request</span><span class="p">.</span><span class="nx">url</span><span class="si">}</span><span class="sb"> until </span><span class="si">${</span><span class="nx">expires</span><span class="p">.</span><span class="nx">toUTCString</span><span class="p">()</span><span class="si">}</span><span class="sb">.`</span><span class="p">,</span>
<span class="w"> </span><span class="p">);</span>
<span class="w"> </span><span class="c1">// Put the duplicated Response in the cache</span>
<span class="w"> </span><span class="nx">cache</span><span class="p">.</span><span class="nx">put</span><span class="p">(</span><span class="nx">request</span><span class="p">,</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">Response</span><span class="p">(</span><span class="nx">body</span><span class="p">,</span><span class="w"> </span><span class="nx">cachedResponseFields</span><span class="p">));</span>
<span class="w"> </span><span class="c1">// Return the live response from the network</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">returnedResponse</span><span class="p">;</span>
<span class="w"> </span><span class="p">});</span>
<span class="w"> </span><span class="p">});</span>
<span class="w"> </span><span class="p">})</span>
<span class="w"> </span><span class="p">)</span>
<span class="w"> </span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div>
<p>The trick here is to recreate a new response with extra <span class="caps">HTTP</span> headers
(<code>SW-Cache-Expires</code>) to keep trace of the cache expiration date. We must be
careful here not to use an <span class="caps">HTTP</span> header name which could conflict with a real
<span class="caps">HTTP</span> header (or the information sent by the server would be lost).</p>
<p>When fetching a new item, we first try to match it with the cache. If a
response is already cached, we check its expiration datetime and eventually
return it. Only if no matching response (or an expired one) is found in the
cache, we fetch from the network.</p>
<p><em>Note:</em> We could use the same strategy to actually enforce a <code>Cache-Control</code>
or <code>Expires</code> <span class="caps">HTTP</span> header and let the browser handle all the caching for us.
However, with this setup, we would not be able to have full control of the
cache strategy and enforce the browser to actually serve the local cached
response instead of trying to fetch the online response when there are network issues.</p>
<p>Finally, we have to manage the cache expiration manually. This can be easily
done at startup of your app using a
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API">message</a>.</p>
<div class="highlight"><pre><span></span><code><span class="nb">global</span><span class="p">.</span><span class="nx">self</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="s1">'message'</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="nx">event</span><span class="p">)</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`SW: received message </span><span class="si">${</span><span class="nx">event</span><span class="p">.</span><span class="nx">data</span><span class="si">}</span><span class="sb">.`</span><span class="p">);</span>
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">eventData</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">data</span><span class="p">);</span>
<span class="w"> </span><span class="c1">// Clean tiles cache when we receive the message asking to do so</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">eventData</span><span class="p">.</span><span class="nx">action</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="s1">'PURGE_EXPIRED_TILES'</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">DEBUG</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'SW: purging expired tiles from cache.'</span><span class="p">);</span>
<span class="w"> </span><span class="nb">global</span><span class="p">.</span><span class="nx">caches</span><span class="p">.</span><span class="nx">open</span><span class="p">(</span><span class="sb">`</span><span class="si">${</span><span class="nx">CACHE_NAME</span><span class="si">}</span><span class="sb">-tiles`</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span>
<span class="w"> </span><span class="nx">cache</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">cache</span><span class="p">.</span><span class="nx">keys</span><span class="p">().</span><span class="nx">then</span><span class="p">(</span>
<span class="w"> </span><span class="nx">keys</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">keys</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span>
<span class="w"> </span><span class="c1">// Loop over all requests stored in the cache and get the</span>
<span class="w"> </span><span class="c1">// matching cached response.</span>
<span class="w"> </span><span class="nx">key</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">cache</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="nx">key</span><span class="p">).</span><span class="nx">then</span><span class="p">((</span><span class="nx">cachedResponse</span><span class="p">)</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Check expiration and eventually delete the cached</span>
<span class="w"> </span><span class="c1">// item</span>
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">expirationDate</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Date</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">cachedResponse</span><span class="p">.</span><span class="nx">headers</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'sw-cache-expires'</span><span class="p">));</span>
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">now</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">();</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">expirationDate</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="nx">now</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">DEBUG</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`SW: purging (expired) tile </span><span class="si">${</span><span class="nx">key</span><span class="p">.</span><span class="nx">url</span><span class="si">}</span><span class="sb"> from cache.`</span><span class="p">);</span>
<span class="w"> </span><span class="nx">cache</span><span class="p">.</span><span class="ow">delete</span><span class="p">(</span><span class="nx">key</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}),</span>
<span class="w"> </span><span class="p">),</span>
<span class="w"> </span><span class="p">),</span>
<span class="w"> </span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">});</span>
</code></pre></div>
<p>This can then be called from your client code at startup. For instance, you
can use, in your main <a href="http://vuejs.org/">Vue.<span class="caps">JS</span></a> component</p>
<div class="highlight"><pre><span></span><code><span class="nx">mounted</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Service worker is for caching only here, so it needs both SW support</span>
<span class="w"> </span><span class="c1">// and caching API support.</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="s1">'serviceWorker'</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="nx">navigator</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="s1">'caches'</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="nb">window</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">navigator</span><span class="p">.</span><span class="nx">serviceWorker</span><span class="p">.</span><span class="nx">register</span><span class="p">(</span><span class="s1">'/sw.js'</span><span class="p">).</span><span class="nx">then</span><span class="p">(</span>
<span class="w"> </span><span class="c1">// Clean expired tiles from the cache at startup</span>
<span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="nx">navigator</span><span class="p">.</span><span class="nx">serviceWorker</span><span class="p">.</span><span class="nx">controller</span><span class="p">.</span><span class="nx">postMessage</span><span class="p">(</span><span class="nb">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">({</span>
<span class="w"> </span><span class="nx">action</span><span class="o">:</span><span class="w"> </span><span class="s1">'PURGE_EXPIRED_TILES'</span><span class="p">,</span>
<span class="w"> </span><span class="p">})),</span>
<span class="w"> </span><span class="p">).</span><span class="k">catch</span><span class="p">((</span><span class="nx">error</span><span class="p">)</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="sb">`Registration failed with </span><span class="si">${</span><span class="nx">error</span><span class="si">}</span><span class="sb">.`</span><span class="p">);</span>
<span class="w"> </span><span class="p">});</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">},</span>
</code></pre></div>
<p>The full code of this Service Worker can be found
<a href="https://framagit.org/phyks/cygnal/blob/07ab80542db1903e3fb8cfa2a1298f0ca441ac08/src/sw.js">here</a>.</p>
<p>As a bonus, here is a little snippet based on
<a href="https://github.com/lukechilds/expired"><code>expired</code></a> to get the time before
expiration of a response, according to <span class="caps">HTTP</span> headers:</p>
<div class="highlight"><pre><span></span><code><span class="c1">// Get duration (in s) before (cache) expiration from headers of a fetch</span>
<span class="c1">// request.</span>
<span class="kd">function</span><span class="w"> </span><span class="nx">getExpiresFromHeaders</span><span class="p">(</span><span class="nx">headers</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Try to use the Cache-Control header (and max-age)</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">headers</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'cache-control'</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">maxAge</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">headers</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'cache-control'</span><span class="p">).</span><span class="nx">match</span><span class="p">(</span><span class="sr">/max-age=(\d+)/</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">parseInt</span><span class="p">(</span><span class="nx">maxAge</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="nx">maxAge</span><span class="p">[</span><span class="mf">1</span><span class="p">]</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="mf">0</span><span class="p">,</span><span class="w"> </span><span class="mf">10</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="c1">// Otherwise try to get expiration duration from the Expires header</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">headers</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'expires'</span><span class="p">))</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">(</span>
<span class="w"> </span><span class="nb">parseInt</span><span class="p">(</span>
<span class="w"> </span><span class="p">(</span><span class="ow">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">(</span><span class="nx">headers</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s1">'expires'</span><span class="p">))).</span><span class="nx">getTime</span><span class="p">()</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mf">1000</span><span class="p">,</span>
<span class="w"> </span><span class="mf">10</span><span class="p">,</span>
<span class="w"> </span><span class="p">)</span>
<span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="p">(</span><span class="ow">new</span><span class="w"> </span><span class="nb">Date</span><span class="p">()).</span><span class="nx">getTime</span><span class="p">()</span>
<span class="w"> </span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">null</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>Generating your own vector tiles2018-12-30T23:05:00+01:002018-12-30T23:05:00+01:00Phykstag:localhost,2018-12-30:/Blog/output/2018/12/generating-your-own-vector-tiles.html<p>There is a cycle-oriented OpenStreetMap render available, called
<a href="http://opencyclemap.org/">OpenCycleMap</a>. Sadly, OpenCycleMap is not really
open (as in opensource) and it is not easy to report issues and get bug fixes.
Moreover, you cannot selfhost it and have to
<a href="https://thunderforest.com/pricing/">pay</a> after a given number of requests.</p>
<p>There were discussions recently, on
<a href="https://wiki.openstreetmap.org/wiki/FR:IRC"><code>#osm-fr@oftc.net</code></a> and <a href="https://lists.openstreetmap.org/pipermail/talk-fr/2018-December/091299.html">on the
French <span class="caps">OSM</span>
mailing-list</a>
about eventually having an alternative render dedicated to cycling which would
be totally opensource, free software and selfhostable.</p>
<p>There is a cycle-oriented OpenStreetMap render available, called
<a href="http://opencyclemap.org/">OpenCycleMap</a>. Sadly, OpenCycleMap is not really
open (as in opensource) and it is not easy to report issues and get bug fixes.
Moreover, you cannot selfhost it and have to
<a href="https://thunderforest.com/pricing/">pay</a> after a given number of requests.</p>
<p>There were discussions recently, on
<a href="https://wiki.openstreetmap.org/wiki/FR:IRC"><code>#osm-fr@oftc.net</code></a> and <a href="https://lists.openstreetmap.org/pipermail/talk-fr/2018-December/091299.html">on the
French <span class="caps">OSM</span>
mailing-list</a>
about eventually having an alternative render dedicated to cycling which would
be totally opensource, free software and selfhostable.</p>
<p>This was the occasion to have a first look at tile rendering (and in
particular vector tiles rendering, based on
<a href="http://openmaptiles.org/">OpenMapTiles</a>). Here is a quick getting started guide.</p>
<h2>Vector vs raster tiles</h2>
<p>Many articles are available online about the difference between
<a href="https://en.wikipedia.org/wiki/Vector_tiles">vector</a> and
<a href="https://en.wikipedia.org/wiki/Tiled_web_map">raster</a> (bitmap files) tiles, so
I will not write too much about this here to keep this article short. The
rendering of vector tiles is done on the client side and the tiles are usually
smaller in weight than the equivalent raster tiles.</p>
<p>Let us just sum up the main facts we might use about vector tiles before starting:</p>
<ul>
<li>There are <a href="https://en.wikipedia.org/wiki/Vector_tiles#Standards_and_approaches">quite a
few</a>
different standards and formats for vector tiles. We will focus on the
protocol buffer standard from Mapbox here.</li>
<li>Vector tiles encode geographical data according to a certain schema, which
describes how the vector data is organized into thematic layers and which
attributes are actually included and served to the client. We will focus here
on using the <a href="https://openmaptiles.org/schema/">OpenMapTiles schema</a> which is
a standard and open source schema for vector tiles.</li>
<li>The render of vector tiles on the client side requires a style (which is a
<span class="caps">JSON</span> file encoded according to <a href="https://openmaptiles.org/docs/style/mapbox-gl-style-spec/">Mapbox <span class="caps">GL</span> style
specification</a>).
Using the standard OpenMapTiles schema for the vector tiles means you can
easily re-use <a href="https://openmaptiles.org/styles/">any Open Map Styles</a>.
This also makes it possible to use style editors such as <a href="https://github.com/maputnik/editor">Maputnik
Editor</a> or <a href="https://www.mapbox.com/mapbox-studio/">Mapbox
Studio</a>.</li>
</ul>
<p><em>Note:</em> Using Mapbox specifications just means building on top of their
standard, to be able to reuse the tiles definitions and styles. Using a style
in Mapbox <span class="caps">GL</span> style does not enforce you to use <a href="https://www.mapbox.com/mapbox-gl-js/api/">Mapbox
<span class="caps">GL</span></a> at all. You can still use
<a href="https://github.com/boundlessgeo/ol-mapbox-style">OpenLayers</a> or
<a href="https://openmaptiles.org/docs/website/leaflet/">Leaflet</a>.</p>
<p><em>Note:</em> Using vector tiles and OpenMapTiles schema does not mean you can never
do a raster render. Provided that the style to use is known by the server, it
could do a raster render and serve both vector tiles and raster tiles at the
same time.</p>
<p>OpenMapTiles provide a ready to use self-hostable solution with downloadable
<a href="https://openmaptiles.com/downloads/planet/">vector tiles</a> from their server,
built from <span class="caps">OSM</span> data. Sadly, the free vector tiles are really outdated and
getting up to date tiles is super expensive. This article will focus on
serving OpenMapTiles from an <span class="caps">OSM</span> data export and a regular PostgreSQL /
PostGIS database.</p>
<h2>Requirements</h2>
<p>Let’s start with a Vagrant <span class="caps">VM</span></p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>cat<span class="w"> </span>Vagrantfile
<span class="c1"># -*- mode: ruby -*-</span>
<span class="c1"># vi: set ft=ruby :</span>
Vagrant.configure<span class="o">(</span><span class="s2">"2"</span><span class="o">)</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="p">|</span>config<span class="p">|</span>
<span class="w"> </span><span class="c1"># Use a Ubuntu box</span>
<span class="w"> </span>config.vm.box<span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"ubuntu/bionic64"</span>
<span class="w"> </span><span class="c1"># VM disk size, consider at least 20GB for a regional extract.</span>
<span class="w"> </span>config.disksize.size<span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'40GB'</span>
<span class="w"> </span><span class="c1"># Forward port for Tegola</span>
<span class="w"> </span>config.vm.network<span class="w"> </span><span class="s2">"forwarded_port"</span>,<span class="w"> </span>guest:<span class="w"> </span><span class="m">8080</span>,<span class="w"> </span>host:<span class="w"> </span><span class="m">8080</span>
<span class="w"> </span><span class="c1"># Forward port for Kartotherian</span>
<span class="w"> </span>config.vm.network<span class="w"> </span><span class="s2">"forwarded_port"</span>,<span class="w"> </span>guest:<span class="w"> </span><span class="m">6533</span>,<span class="w"> </span>host:<span class="w"> </span><span class="m">6533</span>
<span class="w"> </span>config.vm.provider<span class="w"> </span><span class="s2">"virtualbox"</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="p">|</span>vb<span class="p">|</span>
<span class="w"> </span><span class="c1"># Memory (RAM) for the VM, 8GB might be overkill</span>
<span class="w"> </span>vb.memory<span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"8000"</span>
<span class="w"> </span>end
end
$<span class="w"> </span><span class="c1"># You will need vagrant-disksize plugin to define the VM disk size.</span>
$<span class="w"> </span>vagrant<span class="w"> </span>plugin<span class="w"> </span>install<span class="w"> </span>vagrant-disksize
$<span class="w"> </span>vagrant<span class="w"> </span>up
$<span class="w"> </span>vagrant<span class="w"> </span>ssh
</code></pre></div>
<p>We can now install PostgreSQL and <a href="http://www.postgis.net/">PostGIS</a> as well
as <a href="http://www.gdal.org/"><span class="caps">GDAL</span></a> and some basic tools</p>
<div class="highlight"><pre><span></span><code>vagrant@ubuntu-bionic:~$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>update
vagrant@ubuntu-bionic:~$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>postgis
vagrant@ubuntu-bionic:~$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>gdal-bin
vagrant@ubuntu-bionic:~$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>wget<span class="w"> </span>build-essential<span class="w"> </span>git<span class="w"> </span>unzip<span class="w"> </span>curl<span class="w"> </span>build-essential<span class="w"> </span>sqlite3
</code></pre></div>
<p>We will also need <a href="https://imposm.org/static/rel/">imposm3</a></p>
<div class="highlight"><pre><span></span><code>vagrant@ubuntu-bionic:~$<span class="w"> </span>wget<span class="w"> </span>https://imposm.org/static/rel/imposm3-0.4.0dev-20170519-3f00374-linux-x86-64.tar.gz
vagrant@ubuntu-bionic:~$<span class="w"> </span>tar<span class="w"> </span>zxvf<span class="w"> </span>imposm3-0.4.0dev-20170519-3f00374-linux-x86-64.tar.gz
vagrant@ubuntu-bionic:~$<span class="w"> </span>rm<span class="w"> </span>imposm3-0.4.0dev-20170519-3f00374-linux-x86-64.tar.gz
vagrant@ubuntu-bionic:~$<span class="w"> </span>mv<span class="w"> </span>imposm3-0.4.0dev-20170519-3f00374-linux-x86-64<span class="w"> </span>imposm3
vagrant@ubuntu-bionic:~$<span class="w"> </span><span class="c1"># Add imposm3 folder to $PATH</span>
vagrant@ubuntu-bionic:~$<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s1">'PATH="$HOME/imposm3:$PATH"'</span><span class="w"> </span>>><span class="w"> </span>.profile
vagrant@ubuntu-bionic:~$<span class="w"> </span><span class="c1"># (Re)source the file to ensure $PATH is correctly set</span>
vagrant@ubuntu-bionic:~$<span class="w"> </span><span class="nb">source</span><span class="w"> </span>.profile
</code></pre></div>
<p><em>Note:</em> The <code>$HOME/imposm3</code> is prepended to <code>$PATH</code> for convenience here, but
it would probably be better to actually install <code>imposm3</code> on the system rather
than putting this user-owned directory in the <code>$PATH</code> in a production setup.</p>
<p>Let us create a user for our PostgreSQL database</p>
<div class="highlight"><pre><span></span><code>vagrant@ubuntu-bionic:~$<span class="w"> </span>sudo<span class="w"> </span>su<span class="w"> </span>postgres
postgres@ubuntu-bionic:~$<span class="w"> </span>psql
<span class="nv">postgres</span><span class="o">=</span><span class="c1"># CREATE USER gis;</span>
CREATE<span class="w"> </span>ROLE
<span class="nv">postgres</span><span class="o">=</span><span class="c1"># ALTER USER gis WITH PASSWORD 'gis';</span>
ALTER<span class="w"> </span>ROLE
<span class="nv">postgres</span><span class="o">=</span><span class="c1"># ALTER USER gis SUPERUSER;</span>
ALTER<span class="w"> </span>ROLE
</code></pre></div>
<p><em>Note:</em> The created user has <code>SUPERUSER</code> powers here, which is just a matter
of convenience for the following parts. This is not a good practice in
production setup.</p>
<h2>Tegola</h2>
<p>A nice and easy to get running setup is relying on
<a href="https://tegola.io/">Tegola</a>. This opensource tile vector server is written in
Go and therefore quite easy to get running on your machine.</p>
<p>The <a href="https://tegola.io/documentation/getting-started/">getting started doc</a> is
very good and should get you a running server for Bonn area in a matter of minutes.</p>
<p>They also have a repository with scripts and explanations to <a href="https://github.com/go-spatial/tegola-osm">import your own
<span class="caps">OSM</span> data</a> in the database and render
tiles using Tegola, which is super convenient to get your first rendered tiles
in your area. They also have <a href="https://github.com/go-spatial/tegola-web-demo/tree/master/styles">some
styles</a> to
use on top of this <span class="caps">OSM</span> data import. Just remember to edit the <a href="https://github.com/go-spatial/tegola-web-demo/blob/master/styles/hot-osm.json#L22"><code>sources</code>
configuration
option</a>
to use your own Tegola server. There is a nice documentation on how to get a
render using these styles in OpenLayers <a href="https://tegola.io/tutorials/tegola-with-olms/">using
<span class="caps">OLMS</span></a>.</p>
<p>Sadly, it seems that the script from Tegola does not follow the <a href="https://openmaptiles.org/schema/">OpenMapTiles
schema</a> and you would have to adapt any
OpenMapTiles style you would want to use (or change the layers in the tiles
served by Tegola).</p>
<h2>Kartotherian</h2>
<p><a href="http://qwant.com/">Qwant</a> recently started a (beta) map service, <a href="https://www.qwant.com/maps/">Qwant
Maps</a>. They published a lot of scripts and
configuration files on <a href="https://github.com/QwantResearch/qwantmaps">Github</a>.
This is a super cool initiative, giving a very quick and easy way to reproduce
their setup and start working with vector tiles. This seemed at this point the
best lead to explore for having a vector tiles server quickly. Thanks a lot to
them for opening all of this!</p>
<p><em>Note</em>: You can also use
<a href="https://github.com/openmaptiles/openmaptiles/blob/master/README.md">openmaptiles</a>
to generate the tiles in a OpenMapTiles compatible way. It runs using Docker.</p>
<p>All the useful config files lie in <a href="https://github.com/QwantResearch/kartotherian_config">this
repository</a>.</p>
<h3>Importing data</h3>
<p>The first step is to import <span class="caps">OSM</span> data in a database. This is handled by <a href="https://github.com/QwantResearch/kartotherian_config/blob/master/import_data/tasks.py">this
script</a>
and the documentation is available
<a href="https://github.com/QwantResearch/kartotherian_config/tree/master/import_data">here</a>.</p>
<p>First, let us install the required dependencies for this script to run:</p>
<div class="highlight"><pre><span></span><code>vagrant@ubuntu-bionic:~$<span class="w"> </span><span class="c1"># Let's install the required osml10n extension for PostgreSQL from</span>
vagrant@ubuntu-bionic:~$<span class="w"> </span><span class="c1"># https://github.com/giggls/mapnik-german-l10n</span>
vagrant@ubuntu-bionic:~$<span class="w"> </span>git<span class="w"> </span>clone<span class="w"> </span>https://github.com/giggls/mapnik-german-l10n
vagrant@ubuntu-bionic:~$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>mapnik-german-l10n
vagrant@ubuntu-bionic:~/mapnik-german-l10n$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>debhelper<span class="w"> </span>libicu-dev<span class="w"> </span>postgresql-server-dev-all<span class="w"> </span>postgresql-server-dev-10<span class="w"> </span>libkakasi2-dev<span class="w"> </span>libutf8proc-dev<span class="w"> </span>pandoc
vagrant@ubuntu-bionic:~/mapnik-german-l10n$<span class="w"> </span>make<span class="w"> </span>deb
vagrant@ubuntu-bionic:~/mapnik-german-l10n$<span class="w"> </span>sudo<span class="w"> </span>dpkg<span class="w"> </span>-i<span class="w"> </span>../postgresql-10-osml10n_2.5.4_amd64.deb
</code></pre></div>
<p>Then, let us create the PostgreSQL database to import data to</p>
<div class="highlight"><pre><span></span><code>vagrant@ubuntu-bionic:~$<span class="w"> </span>sudo<span class="w"> </span>su<span class="w"> </span>postgres
postgres@ubuntu-bionic:/home/vagrant$<span class="w"> </span>psql
<span class="nv">postgres</span><span class="o">=</span><span class="c1"># CREATE DATABASE gis;</span>
CREATE<span class="w"> </span>DATABASE
<span class="nv">postgres</span><span class="o">=</span><span class="c1"># \c gis;</span>
You<span class="w"> </span>are<span class="w"> </span>now<span class="w"> </span>connected<span class="w"> </span>to<span class="w"> </span>database<span class="w"> </span><span class="s2">"gis"</span><span class="w"> </span>as<span class="w"> </span>user<span class="w"> </span><span class="s2">"postgres"</span>.
<span class="nv">gis</span><span class="o">=</span><span class="c1"># CREATE EXTENSION postgis;</span>
CREATE<span class="w"> </span>EXTENSION
<span class="nv">gis</span><span class="o">=</span><span class="c1"># CREATE EXTENSION hstore;</span>
CREATE<span class="w"> </span>EXTENSION
<span class="nv">gis</span><span class="o">=</span><span class="c1"># CREATE EXTENSION unaccent;</span>
CREATE<span class="w"> </span>EXTENSION
<span class="nv">gis</span><span class="o">=</span><span class="c1"># CREATE EXTENSION fuzzystrmatch;</span>
CREATE<span class="w"> </span>EXTENSION
<span class="nv">gis</span><span class="o">=</span><span class="c1"># CREATE EXTENSION osml10n;</span>
CREATE<span class="w"> </span>EXTENSION
</code></pre></div>
<p>Then, let us install the import script and its dependencies</p>
<div class="highlight"><pre><span></span><code>vagrant@ubuntu-bionic:~$<span class="w"> </span><span class="c1"># Make sure to clone Git submodules as well</span>
vagrant@ubuntu-bionic:~$<span class="w"> </span>git<span class="w"> </span>clone<span class="w"> </span>--recurse-submodules<span class="w"> </span>https://github.com/QwantResearch/kartotherian_config
vagrant@ubuntu-bionic:~$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>kartotherian_config/import_data
vagrant@ubuntu-bionic:~/kartotherian_config/import_data$<span class="w"> </span><span class="c1"># Install pip and pipenv</span>
vagrant@ubuntu-bionic:~/kartotherian_config/import_data$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>python-pip
vagrant@ubuntu-bionic:~/kartotherian_config/import_data$<span class="w"> </span>sudo<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>pipenv
vagrant@ubuntu-bionic:~/kartotherian_config/import_data$<span class="w"> </span><span class="c1"># Create the virtualenv</span>
vagrant@ubuntu-bionic:~/kartotherian_config/import_data$<span class="w"> </span>pipenv<span class="w"> </span>install
vagrant@ubuntu-bionic:~/kartotherian_config/import_data$<span class="w"> </span><span class="c1"># Let's install the required pgfutter tool (https://github.com/lukasmartinelli/pgfutter)</span>
vagrant@ubuntu-bionic:~/kartotherian_config/import_data$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span>wget<span class="w"> </span>-O<span class="w"> </span>pgfutter<span class="w"> </span>https://github.com/lukasmartinelli/pgfutter/releases/download/v1.2/pgfutter_linux_amd64<span class="w"> </span><span class="o">&&</span><span class="w"> </span>chmod<span class="w"> </span>+x<span class="w"> </span>pgfutter<span class="w"> </span><span class="o">&&</span><span class="w"> </span>sudo<span class="w"> </span>mv<span class="w"> </span>pgfutter<span class="w"> </span>/usr/bin/
vagrant@ubuntu-bionic:~$<span class="w"> </span><span class="c1"># Let's install the other required dependencies</span>
vagrant@ubuntu-bionic:~$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>osmctools
</code></pre></div>
<p>Let us now configure the import script. In <code>import_data/invoke.yaml</code>, you should:</p>
<ul>
<li>Check your PostgreSQL credentials in the <code>pg:</code> section (only <code>host</code> which
should be <code>localhost</code> if you followed this guide).</li>
<li>Set the <span class="caps">URL</span> of the <span class="caps">OSM</span> export to use, in the <code>osm:</code> section. You can use any
export from <a href="https://download.geofabrik.de/">Geofabrik</a> for instance.
Consider using a small extract (like regional one) to start with.</li>
<li>Finally, create a <code>/data</code> folder to store generated files:
<code>sudo mkdir /data && sudo chown vagrant:vagrant /data</code>.</li>
</ul>
<p><em>Note:</em> You should also update the <code>main_dir</code> and <code>sql_dir</code> configuration
entries in <code>import_data/invoke.yaml</code> to point to
<code>/home/vagrant/kartotherian_config/imposm</code>. You should also replace the
<code>language.sql</code>, <code>postgis-vt-util.sql</code>, <code>import-water.sh</code> and
<code>import_osmborder_lines.py</code> paths in the <code>import_data/tasks.py</code> file by
<code>../external-dependencies/import-sql/language.sql</code>,
<code>../external-dependencies/postgis-vt-util/postgis-vt-util.sql</code>,
<code>../external-dependencies/import-water/import-water.sh</code> and
<code>../external-dependencies/import-osmborder/import/import_osmborder_lines.sh</code>.
This is done in <a href="https://github.com/QwantResearch/kartotherian_config/pull/44/files">this
<span class="caps">PR</span></a> which
might get merged at some point.</p>
<p>Finally, we can run the import of <span class="caps">OSM</span> data. This will download the latest <span class="caps">OSM</span>
dump specified in the configuration and import it along the other required data.</p>
<div class="highlight"><pre><span></span><code>vagrant@ubuntu-bionic:~/kartotherian_config/import_data$<span class="w"> </span><span class="c1"># Make sure to run the</span>
vagrant@ubuntu-bionic:~/kartotherian_config/import_data$<span class="w"> </span><span class="c1"># pipenv command from the import_data folder.</span>
vagrant@ubuntu-bionic:~/kartotherian_config/import_data$<span class="w"> </span>pipenv<span class="w"> </span>run<span class="w"> </span>invoke
</code></pre></div>
<h3>Install kartotherian</h3>
<p>Then, let us install
<a href="https://github.com/kartotherian/kartotherian">Kartotherian</a> to serve the
vector tiles using data from the database.</p>
<div class="highlight"><pre><span></span><code>vagrant@ubuntu-bionic:~$<span class="w"> </span><span class="nb">cd</span>
vagrant@ubuntu-bionic:~$<span class="w"> </span>git<span class="w"> </span>clone<span class="w"> </span>https://github.com/kartotherian/kartotherian
vagrant@ubuntu-bionic:~$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>kartotherian
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="c1"># Let us install NodeJS. Careful to take version 8</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="c1"># and not above. This does not work with the `nodejs`</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="c1"># version from the official repositories.</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span>curl<span class="w"> </span>-sL<span class="w"> </span>https://deb.nodesource.com/setup_8.x<span class="w"> </span><span class="p">|</span><span class="w"> </span>sudo<span class="w"> </span>-E<span class="w"> </span>bash<span class="w"> </span>-
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>nodejs
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="c1"># Install the rest of dependencies</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>pkg-config<span class="w"> </span>libcairo2-dev<span class="w"> </span>libjpeg-dev<span class="w"> </span>libgif-dev
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="c1"># Install all the JS dependencies</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span>npm<span class="w"> </span>install
</code></pre></div>
<p>You can check everything is working fine by running <code>node server.js -c
config.external.yaml</code>. This will start the tile server, listening on port
<code>6533</code> and relaying tiles from Wikimedia directly (as a <span class="caps">CDN</span>, not using any
local data). If you go to <code>http://localhost:6533</code> in your browser, you should
see a map background appearing, with tiles from Wikimedia.</p>
<p><em>Note:</em> <strong>This should now <a href="https://github.com/kartotherian/kartotherian/issues/78">be
fixed</a></strong>. There seems
to be an issue with the
<code>node_modules/@kartotherian/snapshot/lib/autoPosition.js</code> file and I had to
edit it to get the Kartotherian server running. Here is the diff</p>
<div class="highlight"><pre><span></span><code><<span class="w"> </span><span class="nv">worldLatLng</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>L.LatLngBounds<span class="o">(</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-90,<span class="w"> </span>-180<span class="w"> </span><span class="o">]</span>,<span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="m">90</span>,<span class="w"> </span><span class="m">180</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="o">)</span>,
---
><span class="w"> </span><span class="nv">worldLatLng</span><span class="w"> </span><span class="o">=</span><span class="w"> </span>new<span class="w"> </span>L.LatLngBounds<span class="o">(</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-90,<span class="w"> </span>-180<span class="w"> </span><span class="o">]</span>,<span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="m">90</span>,<span class="w"> </span><span class="m">180</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="o">)</span><span class="p">;</span>
</code></pre></div>
<h3>Serving tiles using imported data and Kartotherian</h3>
<p>The Qwant setup uses <a href="https://github.com/kartotherian/tilerator">Tilerator</a>
for pre-generating tiles and store them in a
<a href="https://cassandra.apache.org/">Cassandra</a> server.</p>
<p>As we are just experimenting with a small area so far and we are not running
the server in production at all, we can skip this component and serve directly
the tiles from the database (tiles generation will be done at each time and
this will be slower, but this is definitely fine for tests).</p>
<div class="highlight"><pre><span></span><code>vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="c1"># Set a config.yaml file for Kartotherian</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span>cat<span class="w"> </span>config.yaml
<span class="c1"># Number of worker processes to spawn.</span>
<span class="c1"># Set to 0 to run everything in a single process without clustering.</span>
<span class="c1"># Use 'ncpu' to run as many workers as there are CPU units</span>
num_workers:<span class="w"> </span><span class="m">0</span>
<span class="c1"># Log error messages and gracefully restart a worker if v8 reports that it</span>
<span class="c1"># uses more heap (note: not RSS) than this many mb.</span>
worker_heap_limit_mb:<span class="w"> </span><span class="m">250</span>
<span class="c1"># Logger info</span>
logging:
<span class="w"> </span>level:<span class="w"> </span>trace
services:
<span class="w"> </span>-<span class="w"> </span>name:<span class="w"> </span>kartotherian
<span class="w"> </span><span class="c1"># a relative path or the name of an npm package, if different from name</span>
<span class="w"> </span>module:<span class="w"> </span>./app.js
<span class="w"> </span><span class="c1"># per-service config</span>
<span class="w"> </span>conf:
<span class="w"> </span>port:<span class="w"> </span><span class="m">6533</span>
<span class="w"> </span><span class="c1"># the location of the spec, defaults to spec.yaml if not specified</span>
<span class="w"> </span>spec:<span class="w"> </span>./spec.template.yaml
<span class="w"> </span><span class="c1"># allow cross-domain requests to the API (default '*')</span>
<span class="w"> </span>cors:<span class="w"> </span><span class="s1">'*'</span>
<span class="w"> </span><span class="c1"># Kartotherian variables and sources</span>
<span class="w"> </span>variables:<span class="w"> </span><span class="o">{</span>
<span class="w"> </span><span class="s1">'osmdb-user'</span>:<span class="w"> </span><span class="s1">'gis'</span>,
<span class="w"> </span><span class="s1">'osmdb-pswd'</span>:<span class="w"> </span><span class="s1">'gis'</span>,
<span class="w"> </span><span class="s1">'osmdb-host'</span>:<span class="w"> </span><span class="s1">'localhost'</span>,
<span class="w"> </span><span class="s1">'cassandra-servers'</span>:<span class="w"> </span><span class="o">[</span><span class="s1">'localhost:9042'</span><span class="o">]</span>,
<span class="w"> </span><span class="s1">'cassandra-user'</span>:<span class="w"> </span><span class="s1">''</span>,
<span class="w"> </span><span class="s1">'cassandra-pswd'</span>:<span class="w"> </span><span class="s1">''</span>
<span class="w"> </span><span class="o">}</span>
<span class="w"> </span>sources:<span class="w"> </span>/home/vagrant/kartotherian_config/tilerator/sources.yaml
<span class="w"> </span>modules:
<span class="w"> </span>-<span class="w"> </span><span class="s2">"tilelive-tmstyle"</span>
<span class="w"> </span>-<span class="w"> </span><span class="s2">"@kartotherian/autogen"</span>
<span class="w"> </span>-<span class="w"> </span><span class="s2">"@kartotherian/babel"</span>
<span class="w"> </span>-<span class="w"> </span><span class="s2">"@kartotherian/cassandra"</span>
<span class="w"> </span>-<span class="w"> </span><span class="s2">"@kartotherian/layermixer"</span>
<span class="w"> </span>-<span class="w"> </span><span class="s2">"@kartotherian/overzoom"</span>
<span class="w"> </span>-<span class="w"> </span><span class="s2">"@kartotherian/postgres"</span>
<span class="w"> </span>-<span class="w"> </span><span class="s2">"@kartotherian/substantial"</span>
<span class="w"> </span>-<span class="w"> </span><span class="s2">"@kartotherian/tilelive-tmsource"</span>
<span class="w"> </span>-<span class="w"> </span><span class="s2">"@kartotherian/tilelive-vector"</span>
<span class="w"> </span>-<span class="w"> </span><span class="s2">"@mapbox/tilejson"</span>
<span class="w"> </span>requestHandlers:
<span class="w"> </span>-<span class="w"> </span><span class="s2">"@kartotherian/maki"</span>
<span class="w"> </span>-<span class="w"> </span><span class="s2">"@kartotherian/snapshot"</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="c1"># Edit kartotherian_config files</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>~/kartotherian_config/tilerator
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="c1"># Edit the DB credentials (user, password, host) in the tm2source files</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="nv">$EDITOR</span><span class="w"> </span>data_tm2source_*.yml
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="c1"># Edit the paths to tm2source files in sources.yaml</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="nv">$EDITOR</span><span class="w"> </span>sources.yaml
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="c1"># Install Cassandra (https://cassandra.apache.org/download/)</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="c1"># Cassandra is not necessarily needed</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="c1"># but having it will avoid printing useless errors in Kartotherian output.</span>
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"deb http://www.apache.org/dist/cassandra/debian 311x main"</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sudo<span class="w"> </span>tee<span class="w"> </span>-a<span class="w"> </span>/etc/apt/sources.list.d/cassandra.sources.list
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span>curl<span class="w"> </span>https://www.apache.org/dist/cassandra/KEYS<span class="w"> </span><span class="p">|</span><span class="w"> </span>sudo<span class="w"> </span>apt-key<span class="w"> </span>add<span class="w"> </span>-
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>update
vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>cassandra
</code></pre></div>
<p>Finally, we can start the <code>Kartotherian</code> server:</p>
<div class="highlight"><pre><span></span><code>vagrant@ubuntu-bionic:~/kartotherian$<span class="w"> </span>npm<span class="w"> </span>start
</code></pre></div>
<h3>Rendering tiles in the browser</h3>
<p>Kartotherian serves a demo interface to check tiles generation is working on
<code>http://localhost:6533</code>. Sadly, it seems this is only working with <code>png</code> tiles
and not with vector tiles only such as our setup. This is not a big deal and
getting a first render is quite simple though :)</p>
<p>First, let us create a base <span class="caps">HTML</span> page with an OpenLayers map:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>cat<span class="w"> </span>index.html
<!doctype<span class="w"> </span>html>
<html<span class="w"> </span><span class="nv">lang</span><span class="o">=</span><span class="s2">"en"</span>>
<span class="w"> </span><head>
<span class="w"> </span><link<span class="w"> </span><span class="nv">rel</span><span class="o">=</span><span class="s2">"stylesheet"</span><span class="w"> </span><span class="nv">href</span><span class="o">=</span><span class="s2">"https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/css/ol.css"</span><span class="w"> </span><span class="nv">type</span><span class="o">=</span><span class="s2">"text/css"</span>>
<span class="w"> </span><style>
<span class="w"> </span><span class="c1">#map{height:600px;width:100%;}</span>
<span class="w"> </span></style>
<span class="w"> </span><script<span class="w"> </span><span class="nv">src</span><span class="o">=</span><span class="s2">"https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"</span>></script>
<span class="w"> </span><script<span class="w"> </span><span class="nv">src</span><span class="o">=</span><span class="s2">"https://cdn.jsdelivr.net/npm/ol-mapbox-style@3.5.0/dist/olms.js"</span><span class="w"> </span><span class="nv">type</span><span class="o">=</span><span class="s2">"text/javascript"</span>></script>
<span class="w"> </span><title>OpenLayers<span class="w"> </span>example</title>
<span class="w"> </span></head>
<span class="w"> </span><body>
<span class="w"> </span><div<span class="w"> </span><span class="nv">id</span><span class="o">=</span><span class="s2">"map"</span>></div>
<span class="w"> </span><script<span class="w"> </span><span class="nv">type</span><span class="o">=</span><span class="s2">"text/javascript"</span>>
<span class="w"> </span>olms.apply<span class="o">(</span><span class="s1">'map'</span>,<span class="s1">'style.json'</span><span class="o">)</span><span class="p">;</span>
<span class="w"> </span></script>
<span class="w"> </span></body>
</html>
</code></pre></div>
<p>Then, we need a style for the vector tiles render. You can use <a href="https://openmaptiles.org/styles/">any style from
OpenMapTiles</a> or the <a href="https://github.com/QwantResearch/qwant-basic-gl-style">custom map style from
Qwant</a>. For instance,
let us use the <a href="https://github.com/openmaptiles/osm-bright-gl-style"><span class="caps">OSM</span> Bright style</a>.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>curl<span class="w"> </span><span class="s2">"https://raw.githubusercontent.com/openmaptiles/osm-bright-gl-style/master/style.json"</span><span class="w"> </span>><span class="w"> </span>style.json
$<span class="w"> </span><span class="c1"># Edit the "url" key under the "sources" and set it to your Kartotherian server:</span>
$<span class="w"> </span><span class="c1"># "url": "/info.json"</span>
$<span class="w"> </span><span class="c1"># (see below)</span>
$<span class="w"> </span><span class="c1"># Also remove the `sprite` and `glyphs` lines in the `style.json` file.</span>
$<span class="w"> </span><span class="c1"># These are not working and the style is usable for testing purposes without</span>
$<span class="w"> </span><span class="c1"># them.</span>
$<span class="w"> </span><span class="nv">$EDITOR</span><span class="w"> </span>style.json
</code></pre></div>
<p><em>Note</em>: There seems to be an issue with the <code>style.json</code> not being a correctly
formatted <span class="caps">JSON</span> file at the time of writing this article. I had to replace
<a href="https://github.com/openmaptiles/osm-bright-gl-style/blob/master/style.json#L49">this
line</a>
with <code>"layers": [{</code> (note the extra bracket). See <a href="https://github.com/openmaptiles/osm-bright-gl-style/issues/19">this
issue</a> or <a href="https://github.com/openmaptiles/osm-bright-gl-style/pull/21">this
<span class="caps">PR</span></a>.</p>
<p>Then, we need to fetch the TileJSON describing the available tiles:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>curl<span class="w"> </span>http://localhost:6533/gen_basemap/info.json<span class="w"> </span>><span class="w"> </span>info.json
$<span class="w"> </span><span class="c1"># Add</span>
$<span class="w"> </span><span class="c1"># , "tiles": ["http://localhost:6533/gen_basemap/{z}/{x}/{y}.pbf"]</span>
$<span class="w"> </span><span class="c1"># at the end of the file, before the last closing "}"</span>
$<span class="w"> </span><span class="nv">$EDITOR</span><span class="w"> </span>info.json
</code></pre></div>
<p><em>Note</em>: I guess you could use <code>http://localhost:6533/gen_basemap/info.json</code> in
the <code>style.json</code> file directly. Sadly, this <span class="caps">JSON</span> file does not contain the
tiles <span class="caps">URL</span> and OpenLayers could not render correctly then. I’m not exactly sure
why this is happening yet.</p>
<p><em>Note</em>: Kartotherian config defines <a href="https://github.com/QwantResearch/kartotherian_config/blob/master/tilerator/sources.yaml">many
available
sources</a>.
The two main ones are the <code>lite</code> variant for mobile devices and the <code>basemap</code>
variant for regular devices. The Qwant setup is using
<a href="https://github.com/kartotherian/tilerator">Tilerator</a> to pre-generate all the
tiles and store them in Cassandra (with the <code>gen_basemap</code> source). Then, the
<code>basemap</code> source can be used. As we use directly Kartotherian with this
configuration file, we are directly using the <code>gen_basemap</code> source to have
live generation of the tiles. POIs are in a different layer (<code>gen_poi</code> /
<code>poi</code>) so they will not be displayed on our vector tiles.</p>
<p>Finally, just start your webserver to access <code>index.html</code> file or use
<code>python3 -m http.server</code> and head to <code>http://localhost:8000</code>. Here you go, you
should have a map with a live render of your vector tiles! Note that tiles
generation is done on demand and this could take a bit of time depending on
your computer power.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/12/kartotherian_world.png" title="Rendu du monde">
<img
src="http://localhost/Blog/output/images/2018/12/kartotherian_world.png"
style="max-width: 50%"
alt="Rendu du monde" />
</a>
</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/12/kartotherian_paris.png" title="Rendu autour de Paris">
<img
src="http://localhost/Blog/output/images/2018/12/kartotherian_paris.png"
style="max-width: 50%"
alt="Rendu autour de Paris" />
</a>
</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/12/kartotherian_montrouge.png" title="Rendu de Montrouge">
<img
src="http://localhost/Blog/output/images/2018/12/kartotherian_montrouge.png"
style="max-width: 50%"
alt="Rendu de Montrouge" />
</a>
</p>
<h2>Next steps</h2>
<p>Now, next steps will be the extension of the <a href="https://openmaptiles.org/schema/">OpenMapTiles
schema</a> to include cycling data (no such
info is embedded at the moment). Then, there should be a custom style to have
a render similar to OpenCycleMap, with emphasis on the cycle infrastructure.</p>
<p>There will probably be more articles in this series to cover this :)</p>Suivi des passages de bus à partir des données ouvertes d’IDFM2018-12-16T23:30:00+01:002018-12-16T23:30:00+01:00Phykstag:localhost,2018-12-16:/Blog/output/2018/12/suivi-des-passages-de-bus-a-partir-des-donnees-ouvertes-didfm.html<p><a href="https://fr.wikipedia.org/wiki/%C3%8Ele-de-France_Mobilit%C3%A9s">Île-de-France
Mobilités</a>
(anciennement <span class="caps">STIF</span>) propose des <a href="https://api-lab-trone-stif.opendata.stif.info/pages/api-test-temps-reel/">APIs de
test</a>
des passages en temps réel sur leur réseau (gratuite jusqu’à 200 000 appels
pour une ligne et un arrêt par jour, ou 1000 appels par jour pour avoir
l’aperçu global sur tout le réseau). On peut donc accéder facilement …</p><p><a href="https://fr.wikipedia.org/wiki/%C3%8Ele-de-France_Mobilit%C3%A9s">Île-de-France
Mobilités</a>
(anciennement <span class="caps">STIF</span>) propose des <a href="https://api-lab-trone-stif.opendata.stif.info/pages/api-test-temps-reel/">APIs de
test</a>
des passages en temps réel sur leur réseau (gratuite jusqu’à 200 000 appels
pour une ligne et un arrêt par jour, ou 1000 appels par jour pour avoir
l’aperçu global sur tout le réseau). On peut donc accéder facilement aux
données affichées sur les arrêts de bus avec les temps d’attente avant les
prochains passages.</p>
<p>Il y a <a href="https://www.openstreetmap.org/relation/1253995#map=13/48.8475/2.3191">un
bus</a> que
je connais bien qui est particulièrement irrégulier, avec souvent des temps
d’attente de l’ordre de la demi-heure entre deux bus et plusieurs bus qui
arrivent en même temps. Pourrait-on utiliser cette <span class="caps">API</span> pour étudier ce qu’il
en est en pratique et vérifier si l’impression d’irrégularité n’est qu’une
impression ou vraiment vérifiée ?</p>
<p><strong>Note</strong>: Attention, je ne regarde que les passages de bus que je peux déduire
des données fournies par ces APIs (temps de passage du prochain bus). Des bus
qui se suivent peuvent donc être ratés et considérés comme un seul bus.
D’autre part, il y a <a href="https://www.openstreetmap.org/way/620811969">des travaux à
Montrouge</a>, à proximité de
l’arrêt que je surveille. Tout le code pour reproduire ces résultats est
disponible sur <a href="https://framagit.org/phyks/idfm-bus68">ce dépôt</a>. N’hésitez
pas à le corriger ou le réutiliser.</p>
<p>On peut alors regarder les temps d’attente affichés pour un arrêt donné, au
cours de la journée (ici pour la journée du 15 novembre 2018). Chaque flèche
noire correspond à un passage de bus. Chaque flèche rouge correspond à un
passage de bus possiblement raté (temps d’attente qui augmente au lieu de
décroître). Cette courbe a été obtenue en faisant un appel à l’<span class="caps">API</span> toutes les
minutes pour surveiller l’arrêt <a href="https://www.openstreetmap.org/node/4568993329">“Maurice
Arnoux”</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/12/15_11_2018.png" title="15/11/2018">
<img
src="http://localhost/Blog/output/images/2018/12/15_11_2018.png"
style="max-width: 50%"
alt="15/11/2018" />
</a>
</p>
<p>En regardant la <a href="https://www.ratp.fr/sites/default/files/fiches-horaires/busratp/68.pdf">fiche horaire
officielle</a>,
on voit que le temps de passage devrait être entre 6 et 9 minutes en journée
(entre 7h00 et 20h30) en semaine. Pendant tout le mois de novembre, j’ai
enregistré un point par minute en faisant un appel à l’<span class="caps">API</span> <span class="caps">IDFM</span> pour le bus 68
en direction de “Châtillon-Montrouge” à l’arrêt “Maurice Arnoux”.</p>
<p>On peut ensuite détecter les passages de bus, à partir des données de temps
d’arrivée du prochain bus. Pour simplifier le traitement, je considère que
deux bus qui passeraient à moins d’une minute d’intervalle sont un seul et
même bus. On peut alors tracer l’histogramme des temps de passage entre deux
bus consécutifs en journée, en semaine, au mois de novembre.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/12/bus_68_overview.png" title="Aperçu novembre">
<img
src="http://localhost/Blog/output/images/2018/12/bus_68_overview.png"
style="max-width: 50%"
alt="Aperçu novembre" />
</a>
</p>
<p>Finalement, on peut compter la proportion de bus qui arrivent à moins de 9
minutes d’intervalle et on trouve que cela n’arrive que 47% du temps.</p>Writing a BRouter profile2018-12-13T21:15:00+01:002018-12-13T21:15:00+01:00Phykstag:localhost,2018-12-13:/Blog/output/2018/12/writing-a-brouter-profile.html<p>I recently started to have a deeper look into routing for bikes, on top of
<a href="http://openstreetmap.org/">OpenStreetMap</a> data and came across
<a href="http://brouter.de/">BRouter</a>. This article is a follow-up to the
<a href="http://localhost/Blog/output/2018/11/setting-up-your-own-brouter-instance-and-start-hacking.html">first</a> and
<a href="http://localhost/Blog/output/2018/11/build-your-own-brouter-segments-files.html">second</a> ones and it will quickly cover
how to write your own profile or extend a profile.</p>
<p>I recently started to have a deeper look into routing for bikes, on top of
<a href="http://openstreetmap.org/">OpenStreetMap</a> data and came across
<a href="http://brouter.de/">BRouter</a>. This article is a follow-up to the
<a href="http://localhost/Blog/output/2018/11/setting-up-your-own-brouter-instance-and-start-hacking.html">first</a> and
<a href="http://localhost/Blog/output/2018/11/build-your-own-brouter-segments-files.html">second</a> ones and it will quickly cover
how to write your own profile or extend a profile.</p>
<p>The main (official) documentation about profile development is the
<a href="http://brouter.de/brouter/profile_developers_guide.txt">profile developers
guide</a>. It can be
quite lengthy but covers well all the basis. The main parts you have to worry
about to write your profile is the
<a href="https://github.com/abrensch/brouter/blob/307a50b840c82c1065e4c560b2eda6d53545f548/misc/profiles2/lookups.dat"><code>lookups.dat</code></a> and the <a href="https://github.com/abrensch/brouter/tree/307a50b840c82c1065e4c560b2eda6d53545f548/misc/profiles2">profiles files</a>.</p>
<p>The <code>lookups.dat</code> has already been covered in the <a href="http://localhost/Blog/output/2018/11/build-your-own-brouter-segments-files.html">previous
article</a> of this series. The only
additional point to keep in mind is that when you use aliases in this file,
only the first value will be emitted: <code>zone:maxspeed;0000001616 20 DE:20
FR:20</code> will only emit a single usable value (<code>20</code>) in profile for the three
possible values (<code>20</code>, <code>DE:20</code> and <code>FR:20</code>).</p>
<h2>Quick overview of the key points for writing a BRouter profile</h2>
<p>The <a href="http://brouter.de/brouter/profile_developers_guide.txt">profile developers
guide</a> covers all the
valid expressions in the profile file (variables, operations, etc). Note that
all operators use a prefix notation and not the (rather usual) infix notation.</p>
<p>Let us have a look at the
<a href="https://github.com/abrensch/brouter/blob/307a50b840c82c1065e4c560b2eda6d53545f548/misc/profiles2/trekking.brf#L6-L32"><code>trekking.brf</code></a>
profile. There are three different contexts: global, way and node.</p>
<p>The <a href="https://github.com/abrensch/brouter/blob/307a50b840c82c1065e4c560b2eda6d53545f548/misc/profiles2/trekking.brf#L6-L32"><code>global</code>
context</a>
defines global variables which are used across all the profile and for routing
operations. The full list of available global variables can be found in the
<a href="https://github.com/abrensch/brouter/blob/307a50b840c82c1065e4c560b2eda6d53545f548/brouter-core/src/main/java/btools/router/RoutingContext.java#L120-L188"><code>brouter-core/.../RoutingContext.java#readGlobalConfig</code></a>
file, which is the main routing entry point.</p>
<p>The <a href="https://github.com/abrensch/brouter/blob/307a50b840c82c1065e4c560b2eda6d53545f548/misc/profiles2/trekking.brf#L34-L287"><code>way</code>
context</a>
defines the cost (penalties) for <span class="caps">OSM</span> ways (road segments). Let us put aside
the “classifier” variables for the moment.</p>
<p>Ways and nodes are processed by the
<a href="https://github.com/abrensch/brouter/blob/307a50b840c82c1065e4c560b2eda6d53545f548/brouter-core/src/main/java/btools/router/StdPath.java"><code>brouter-core/StdPath.java</code></a>
(<code>processWaySection</code> and <code>processTargetNode</code>) and
<a href="https://github.com/abrensch/brouter/blob/307a50b840c82c1065e4c560b2eda6d53545f548/brouter-core/src/main/java/btools/router/KinematicPath.java"><code>brouter-core/.../KinematicPath.java</code></a>
(same methods). <code>StdPath.java</code> is used by default, <code>KinematicPath.java</code> is
used for profiles relying on the Kinematic model, such as <a href="https://github.com/abrensch/brouter/blob/307a50b840c82c1065e4c560b2eda6d53545f548/misc/profiles2/car-fast.brf#L8"><code>car-fast.brf</code>
profile</a>.</p>
<p>The main variables to assign in the <code>way</code> context are:</p>
<ul>
<li><a href="https://github.com/abrensch/brouter/blob/307a50b840c82c1065e4c560b2eda6d53545f548/misc/profiles2/trekking.brf#L67-L69"><code>turncost</code></a>
which is the cost for a 90° turn (cost of a turn is <code>turncost * cos(angle)</code>).</li>
<li><a href="https://github.com/abrensch/brouter/blob/307a50b840c82c1065e4c560b2eda6d53545f548/misc/profiles2/trekking.brf#L85-L87"><code>initialcost</code></a>
which is a constant initial cost for a way.</li>
<li><a href="https://github.com/abrensch/brouter/blob/307a50b840c82c1065e4c560b2eda6d53545f548/misc/profiles2/trekking.brf#L160"><code>costfactor</code></a>
which is a cost proportional to the length of the way and is actually the main
cost source.</li>
</ul>
<p>In the <code>node</code> context, only <code>initialcost</code> is to be filled.</p>
<h2>Personal tips for writing BRouter profiles</h2>
<p>Here is a quick list of personal tips after writing and contributing to some
BRouter profiles (and reviewing a bunch of them!):</p>
<ul>
<li>There are <a href="https://github.com/abrensch/brouter/blob/307a50b840c82c1065e4c560b2eda6d53545f548/misc/profiles2/">a
lot</a>,
<a href="https://github.com/abrensch/brouter/pull/103">really a lot</a>,
<a href="https://github.com/zossebart/brouter-mtb">quite</a>
<a href="https://github.com/ThomasTraber/brouter_profiles_and_testing">too</a>
<a href="https://github.com/utack/utack_brouter_data">many</a>, <a href="https://github.com/poutnikl/Brouter-profiles/tree/master/BikeProfiles">really too
many</a>
profiles out there. This is a personal view but I rather believe in a “one
size fits all” approach for BRouter profiles than a super optimized
profile for each possible use case, including the current weather. Plus
having many variables means you are likely to over-optimize for your
specific route and the profile will not be easily reusable.</li>
<li>When testing your profile on routes, try to use diverse routes and check on
the full set. Optimizing for a particular use case might actually be
over-optimization and is likely to give bad results on other routes.</li>
<li><a href="https://github.com/nrenner/brouter-web"><code>brouter-web</code></a> has a “Data” tab
which gives the complete details of the current route and the associated
costs. Coupled with putting waypoints to force a particular route, it is
really a super valuable tool to write profiles and find about costs!</li>
</ul>
<h2>Unit-testing BRouter profiles for easier development</h2>
<p>Wetneb introduced the idea of having a kind of unit-testing to help writing
profiles in <a href="https://github.com/abrensch/brouter/issues/116">this issue</a>. This
is a super useful idea indeed, to be able to compare profiles and prevent
regressions when tweaking variables.</p>
<p>I am currently using <a href="https://github.com/Phyks/BrouterTesting">this iPython
notebook</a> to check my profiles and
ensure they behave correctly.</p>
<p>In this notebook, I tried to have a mix of routes and edge cases to cover
typical use cases and ensure my profile is not overfitting for a particular
use case:</p>
<ul>
<li>Complete routes I am familiar with, either in large city (Paris), medium
sized city (Clermont-Ferrand), following bike routes (cycle travel) and in
the countryside (out of marked bike routes).</li>
<li>Tests on specific features. For these tests, you should take care to have a
“stable” route meaning that if you move slightly the start or end point
for your edge case, the BRouter route is not moving, so that the test can
actually be significant (and avoid hysteretic behavior).</li>
</ul>
<p>These tests should be run using a <a href="https://pub.phyks.me/brouter-testing/segments4/">predefined set of <code>segments4</code>
files</a> to ensure the results
are stable (as <span class="caps">OSM</span> data may evolve in time). All instructions on using it
should be available <a href="https://github.com/Phyks/BrouterTesting/blob/master/BrouterTesting.ipynb">in the
notebook</a>.</p>
<p>Feel free to reuse these tests for your own profiles. I’ll gladly take any <span class="caps">PR</span>
to improve coverage!</p>Build your own BRouter segments files2018-11-10T00:00:00+01:002018-11-10T00:00:00+01:00Phykstag:localhost,2018-11-10:/Blog/output/2018/11/build-your-own-brouter-segments-files.html<p>I recently started to have a deeper look into routing for bikes, on top of
<a href="http://openstreetmap.org/">OpenStreetMap</a> data and came across
<a href="http://brouter.de/">BRouter</a>. This article is a follow-up to the <a href="http://localhost/Blog/output/2018/11/setting-up-your-own-brouter-instance-and-start-hacking.html">first
one</a> and will cover how to build your own <code>segments</code>
files and add new tags to be extracted from the <span class="caps">OSM</span> data for your profiles.</p>
<p>I recently started to have a deeper look into routing for bikes, on top of
<a href="http://openstreetmap.org/">OpenStreetMap</a> data and came across
<a href="http://brouter.de/">BRouter</a>. This article is a follow-up to the <a href="http://localhost/Blog/output/2018/11/setting-up-your-own-brouter-instance-and-start-hacking.html">first
one</a> and will cover how to build your own <code>segments</code>
files and add new tags to be extracted from the <span class="caps">OSM</span> data for your profiles.</p>
<h2>Building BRouter files</h2>
<p>BRouter uses its own data format (<code>.rd5</code> files), split in tiles of 5 x 5
in latitude and longitude. You can download the official tiles from
<a href="http://brouter.de/brouter/segments4/">brouter.de</a> but you can also build them
yourself from an <span class="caps">OSM</span> dump.</p>
<p><span class="caps">OSM</span> dumps are available from <a href="https://planet.osm.org/">planet.osm.org</a> (for
the full planet files) or geographical extracts are provided by
<a href="https://download.geofabrik.de/">Geofabrik</a>.</p>
<h3>Build the pbfparser</h3>
<p>First, there are two file formats available to download <span class="caps">OSM</span> data: <code>bzip</code>-ed
<span class="caps">XML</span> files (very large) and <code>.pbf</code>
(<a href="https://github.com/protocolbuffers/protobuf">Protobuf</a> format) which is much
more efficient. If you want to use the latter one, you will have to build the
<code>pbfparser</code> (in <code>misc/pbfparser</code> first):</p>
<ul>
<li>Download <a href="https://bretth.dev.openstreetmap.org/osmosis-build/osmosis-latest.zip">the latest
version</a>
of <a href="https://wiki.openstreetmap.org/wiki/Osmosis">Osmosis</a> and unzip it somewhere.</li>
<li>Copy the <code>lib/default/protobuf-java-*.jar</code> and
<code>lib/default/osmosis-osm-binary-*.jar</code> files from the unzipped Osmosis
archive to <code>misc/pbfparser/protobuf.jar</code> and <code>misc/pbfparser/osmosis.jar</code>.</li>
<li>Build <code>brouter-server</code> (as we did in the previous article) and copy
<code>brouter-server/target/brouter-server-*-jar-with-dependencies.jar</code> to
<code>misc/pbfparser/brouter.jar</code>.</li>
<li>You can build the <code>pbfparser</code> using, in the <code>misc/pbfparser/</code>
folder,</li>
</ul>
<div class="highlight"><pre><span></span><code>javac -d . -cp "brouter.jar:protobuf.jar:osmosis.jar" *.java
</code></pre></div>
<ul>
<li>Finally, you can build a <code>jar</code> file from these files using</li>
</ul>
<div class="highlight"><pre><span></span><code><span class="n">jar</span><span class="w"> </span><span class="n">cf</span><span class="w"> </span><span class="n">pbfparser</span><span class="o">.</span><span class="n">jar</span><span class="w"> </span><span class="n">btools</span><span class="o">/**/*.</span><span class="k">class</span>
</code></pre></div>
<p><em>Note:</em> If the <code>jar</code> file is not properly created, everything else will seem
to work normally but there will not be any data extracted from the <span class="caps">OSM</span> data
dump. You can check what is actually inside the built <code>jar</code> file using <code>jar tf
pbfparser.jar</code>.</p>
<p>You can now move the files <code>brouter.jar</code>, <code>protobuf.jar</code>, <code>pbfparser.jar</code> and
<code>osmosis.jar</code> from the <code>misc/pbfparser</code> folder to the
<code>misc/scripts/mapcreation</code> folder.</p>
<h3>Run the map creation script</h3>
<p>You can now run the <code>misc/scripts/mapcreation/process_pbf_planet.sh</code> script to
build the segments.</p>
<p>Here are a few useful tips before running it:
* Checkout <a href="https://github.com/abrensch/brouter/pull/121">this <span class="caps">PR</span></a> which improves
a lot the script and adds documentation.
* The script should be run from the <code>misc/scripts/mapcreation</code> folder.
* Have a look at the variables defined at the beginning of the files and
overwrite them according to your needs.
* The script is meant to be used for the BRouter production setup. You likely
want to comment the beginning (downloading of the whole planet file and
removal of the previous segments) and the very least (copy of the
generated segments to the webserver location).</p>
<p><em>Note:</em> It is possible that you encounter an error complaining about not being
able to run <code>bash^M</code>. You can fix this one by running <code>sed -i -e 's/\r$//'
process_pbf_planet.sh</code>.</p>
<p>Beware of the size and requirements to handle the
whole planet file, it might be better to start with a regional extract from
<a href="geofabrik.de">geofabrik.de</a>.</p>
<p>If you want to have elevation information in the generated segments files, you
should download the required <a href="https://cgiarcsi.community/data/srtm-90m-digital-elevation-database-v4-1/"><span class="caps">SRTM</span>
files</a>.
Any flavor of the 90m <span class="caps">SRTM</span> database should be working, but the one used by the
official BRouter segments files are the ones provided by
<a href="https://cgiarcsi.community/data/srtm-90m-digital-elevation-database-v4-1/"><span class="caps">CGIAR</span></a>.
If you are working with rather small geographical extracts, you can download
tiles manually using <a href="http://srtm.csi.cgiar.org/SELECTION/inputCoord.asp">this
interface</a> (use the
“ArcInfo <span class="caps">ASCII</span>” format), instead of having to ask for an access for bulk
download of data. There is no need to unzip the downloaded files, the
<code>process_pbf_planet.sh</code> script expects a folder with all the <span class="caps">ZIP</span> files inside
and will manage it.</p>
<p>Note that if you don’t have the <span class="caps">SRTM</span> data available, the segments files will
still be generated without any issue (but they will miss the elevation data).
If you are not sure which <span class="caps">SRTM</span> files you have to download, you can run the
script once and it will log all the <span class="caps">SRTM</span> files it is looking for. Also note
that there will not be any error shown if you miss a <span class="caps">SRTM</span> file.</p>
<h2>Custom <code>lookups.dat</code></h2>
<p>Now that we know how to build our own segments files for BRouter, we can start
hacking the <code>lookups.dat</code> file to add new tags that we may need.</p>
<p>A very good introduction to the <code>lookups.dat</code> file (not really easy to read,
but is full of useful information) is <a href="http://brouter.de/brouter/profile_developers_guide.txt">the <code>profile_developers_guide.txt</code>
file</a>. The main points
to keep in mind are:</p>
<ul>
<li>There are two context, delimited by a line starting with <code>--- context:</code>.
The <code>way</code> context applies to <span class="caps">OSM</span> ways and the <code>node</code> context defines tag
extraction rules for <span class="caps">OSM</span> nodes.</li>
<li>The <code>lookups.dat</code> has a <code>lookupversion</code> (major version) and a <code>minorversion</code>
defined at the very beginning. Increasing the <code>minorversion</code> means the
change is retro-compatible, increasing the <code>lookupversion</code> means it is
not. This is important for the BRouter app for Android but if you just
play with <code>lookups.dat</code> and <code>brouter-server</code>, this should not matter.</li>
<li>The numbers are an indication of the frequency of this tag in Germany. You
can just put any number and don’t care about this.</li>
<li>You can define aliases in this file by putting multiple tags values on the
same line, separated by a space. For instance</li>
</ul>
<div class="highlight"><pre><span></span><code>busway;0000056005 opposite opposite_lane opposite_track
</code></pre></div>
<p>means it will extract the <code>busway</code> tag values <code>opposite</code>, <code>opposite_lane</code> and
<code>opposite_track</code> and BRouter will expose all these values as the first value,
<code>busway=opposite</code> in this case.</p>
<ul>
<li>Aliases can actually be used with any name to have a custom alias (even if
it is not a known <span class="caps">OSM</span> value). You can use <code>zone:maxspeed;0000001616 20
DE:20 FR:20</code> for instance to have a uniform output (<code>zone:maxspeed=20</code>)
for all the zone with speed limitations of <code>20</code>, no matter the country,
even if there was no tag <code>zone:maxspeed=20</code> within <span class="caps">OSM</span>.</li>
<li>The lookup table used by BRouter afterwards is based on the position of the
tag entry in the <code>lookups.dat</code>. Then, you should add new tags at the end
(of the appropriate context) or replace one of the “dummy” tags that
separate the real way tags from the relation pseudo tags, to make it as
retro-compatible as possible. (See <a href="https://groups.google.com/forum/#!topic/osm-android-bikerouting/x1WOMBqk0FI">this post on the
forum</a>)</li>
<li>Same when you add a tag value to an alias, you should always put the new
value at the end.</li>
</ul>
<p>Note that once you have built the segments files with your new <code>lookups.dat</code>
file and ask a route from <code>brouter-server</code>, it might not output all the newly
added tags values (in the <span class="caps">JSON</span> output, or in the “Data” tab of brouter-web).
This is due to the fact that BRouter only outputs tags which are actually used
by the profile. You can set <code>assign processUnusedTags = true</code> in your profile
to output all tags for the considered ways, even if they were not used (see
the <a href="https://github.com/abrensch/brouter/blob/master/misc/profiles2/dummy.brf">dummy
profile</a>
which can be used for this purpose).</p>
<p>The last article of the serie will be about writing your own profiles and
writing test cases to assist you in this task.</p>Setting up your own BRouter instance and start hacking2018-11-05T23:36:00+01:002018-11-05T23:36:00+01:00Phykstag:localhost,2018-11-05:/Blog/output/2018/11/setting-up-your-own-brouter-instance-and-start-hacking.html<p>I recently started to have a deeper look into routing for bikes, on top of
<a href="http://openstreetmap.org/">OpenStreetMap</a> data and came across
<a href="http://brouter.de/">BRouter</a>. The website and the app might seem old school,
but this is definitely one of the best routing engine out there (especially
for bikes) and it is <span class="caps">FOSS</span>! One of the great advantage of BRouter is that it is
written in Java and is light enough so that it can run on Android devices!</p>
<p>I recently started to have a deeper look into routing for bikes, on top of
<a href="http://openstreetmap.org/">OpenStreetMap</a> data and came across
<a href="http://brouter.de/">BRouter</a>. The website and the app might seem old school,
but this is definitely one of the best routing engine out there (especially
for bikes) and it is <span class="caps">FOSS</span>! One of the great advantage of BRouter is that it is
written in Java and is light enough so that it can run on Android devices!</p>
<p>In this first article, we’ll install our own instance and quickly go through
the various components. In a future article, we’ll focus on profiles and
profile development.</p>
<p><em>Note</em>: My instance is live at <a href="http://brouter.phyks.me/">brouter.phyks.me</a>
(note that the server is not super powerful so the routing computation might
take some time). Segments are available for metropolitan France only. More on
the available profiles at the end of this article.</p>
<h2>Getting the BRouter code and building it</h2>
<p>BRouter code is available <a href="https://github.com/abrensch/brouter">on Github</a>.
There are multiple components (folders) in the repository. The more important are:</p>
<ul>
<li><code>brouter-core</code> (the core logic)</li>
<li><code>brouter-routing-app</code> (the Android part)</li>
<li><code>brouter-server</code> (the <span class="caps">HTTP</span> server which exposes an <span class="caps">HTTP</span> <span class="caps">API</span> on top of Brouter)</li>
<li><code>misc</code> with a lot of utility scripts, profiles and helpers.</li>
</ul>
<p>In this article, we will focus on setting up a web interface for Brouter
(similar to <a href="http://brouter.de/brouter-web/">http://brouter.de/brouter-web/</a>).
We then want to build only the <code>brouter-server</code> part (and its dependencies).
This can be quickly done using:</p>
<div class="highlight"><pre><span></span><code>mvn install -pl brouter-server -am -Dmaven.javadoc.skip=true -DskipTests
</code></pre></div>
<p><em>Note:</em> For those which are not familiar with Java (as I am), <code>mvn install</code>
just builds the code (not actually doing an <code>install</code> as in <code>make install</code>).
<code>-pl brouter-server -am</code> makes it only build <code>brouter-server</code> (and dependencies),
which is required if you don’t want to deal with setting up Android Studio to
correctly build the Android part. <code>-Dmaven.javadoc.skip=true</code> skips the
JavaDoc part (documentation generation from the code, such as Doxygen or
Python Sphinx). <code>-DskipTests</code> do not run the unittests.</p>
<p>You can then run (replace the <code>1.4.11</code> by the current version)</p>
<div class="highlight"><pre><span></span><code><span class="n">java</span><span class="w"> </span><span class="o">-</span><span class="n">Xmx128M</span><span class="w"> </span><span class="o">-</span><span class="n">Xms128M</span><span class="w"> </span><span class="o">-</span><span class="n">Xmn8M</span><span class="w"> </span><span class="o">-</span><span class="n">DmaxRunningTime</span><span class="o">=</span><span class="mi">300</span><span class="w"> </span><span class="o">-</span><span class="n">cp</span><span class="w"> </span><span class="n">brouter</span><span class="o">-</span><span class="n">server</span><span class="o">/</span><span class="n">target</span><span class="o">/</span><span class="n">brouter</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="mf">1.4</span><span class="o">.</span><span class="mi">11</span><span class="o">-</span><span class="n">jar</span><span class="o">-</span><span class="n">with</span><span class="o">-</span><span class="n">dependencies</span><span class="o">.</span><span class="n">jar</span><span class="w"> </span><span class="n">btools</span><span class="o">.</span><span class="n">server</span><span class="o">.</span><span class="n">RouteServer</span><span class="w"> </span><span class="n">misc</span><span class="o">/</span><span class="n">segments4</span><span class="w"> </span><span class="n">misc</span><span class="o">/</span><span class="n">profiles2</span><span class="w"> </span><span class="n">customprofiles</span><span class="w"> </span><span class="mi">17777</span><span class="w"> </span><span class="mi">1</span>
</code></pre></div>
<p>to actually run the server (a very basic <a href="https://github.com/abrensch/brouter/blob/master/misc/scripts/standalone/server.sh">helper
script</a>
is available as well). In this command line, <code>-Xmx128M -Xms128M -Xmn8M
-DmaxRunningTime=300</code> are just the default parameters to limit the memory
consumption. <code>misc/segments4</code>, <code>misc/profiles2</code> and <code>customprofiles</code> are
folder to store the segments file and the profiles (see below). <code>17777</code> is the
port to listen on.</p>
<p><strong><span class="caps">EDIT</span></strong>: <code>customprofiles</code> are profiles written by users and sent to
BRouter-server to use it (through a file upload feature, basically), instead
of limiting the server to the profiles provided by default. In
<a href="http://brouter.de/brouter-web/">Brouter-web</a>, you can access this feature by
clicking the spanner icon on the right hande side. With the previous command
line, uploaded custom profiles will be stored in
<code>misc/profiles2/customprofiles</code>. If you host a production BRouter server, it
is probably a good idea to have a <code>cron</code> task to periodically wipe the content
of <code>customprofiles</code> (or older files in this folder) and to carefully check the
permissions and accesses of files in this folder (as you would do for any file
upload feature).</p>
<p>Your BRouter server is now listening and ready, but we still have to provide
it with <span class="caps">OSM</span> data (segments files) and profiles. Note that this server simply
exposes a <span class="caps">HTTP</span> <span class="caps">API</span> and there is no frontend on top of it at the moment (we
will add one in the end of the article).</p>
<h2>Getting segments files</h2>
<h3>Downloading pre-built segments files</h3>
<p>BRouter extracts the relevant tags and features from <span class="caps">OSM</span> data and encode them
in .rd5 segments files, split in rectangles of 5 degrees of latitude and
longitude. Then, only the relevant part of the map are used, making it lighter.</p>
<p>The segments files are built weekly for the whole planet for the brouter.de
instance and are available at
<a href="http://brouter.de/brouter/segments4/">http://brouter.de/brouter/segments4/</a>.</p>
<p>You can also download only the required files for the geographical area you
wish to cover. For mainland France, this means between latitude 40 and 50 and
between longitude 0 and 5. This can be easily done with the following script:</p>
<div class="highlight"><pre><span></span><code>cd<span class="w"> </span>misc/segments4
for<span class="w"> </span>i<span class="w"> </span>in<span class="w"> </span>$(seq<span class="w"> </span>40<span class="w"> </span>5<span class="w"> </span>50);<span class="w"> </span>do
<span class="w"> </span>for<span class="w"> </span>j<span class="w"> </span>in<span class="w"> </span>$(seq<span class="w"> </span>0<span class="w"> </span>5<span class="w"> </span>5);<span class="w"> </span>do
<span class="w"> </span>wget<span class="w"> </span>-N<span class="w"> </span>"http://brouter.de/brouter/segments4/E<span class="cp">${</span><span class="n">j</span><span class="cp">}</span>_N<span class="cp">${</span><span class="n">i</span><span class="cp">}</span>.rd5"
<span class="w"> </span>done
<span class="w"> </span>wget<span class="w"> </span>-N<span class="w"> </span>"http://brouter.de/brouter/segments4/W5_N<span class="cp">${</span><span class="n">i</span><span class="cp">}</span>.rd5"
done
</code></pre></div>
<p>You can put segments files anywhere you want, but you have to provide the path
of the segments files to the <code>java</code> command-line to start the BRouter server.</p>
<p><strong><span class="caps">EDIT</span></strong>: If you are not sure about the segments files to download, you can
call brouter-server for a specific route in the area you want to cover
(<code>http://localhost:17777/brouter?lonlats=START_LONGITUDE%2CSTART_LATITUE%7CEND_LONGITUDE%2CEND_LATITUDE&profile=trekking&alternativeidx=0&format=geojson</code>, editing latitude and longitude accordingly) and BRouter will answer you back with the missing segments files names.</p>
<h3>Building map segments</h3>
<p>If you would rather build the map segments on your own, rather than
downloading the pre-built one, there is a script in
<a href="https://github.com/abrensch/brouter/blob/master/misc/scripts/mapcreation/process_pbf_planet.sh"><code>misc/scripts/mapcreation</code></a>
to download the latest dump of <span class="caps">OSM</span> data of the planet (or a smaller dump, if
you edit the script accordingly) and process it.</p>
<p><em>Note:</em> If you are curious about the tags and features included in the
segments files, they are defined in the
<a href="https://github.com/abrensch/brouter/blob/master/misc/profiles2/lookups.dat"><code>misc/profiles2/lookups.dat</code></a> file.</p>
<h2>A quick look at profiles</h2>
<p>BRouter has the advantage of offering a nice and easy way to tweak the weights
of road segments through profiles. A default set of profiles is available in
the <code>misc/profiles2</code> folder.</p>
<p>There are also a large number of profiles out there, in particular:</p>
<ul>
<li><a href="https://github.com/poutnikl/Brouter-profiles">poutnikl profiles</a> (for car,
bike or hiking). The car profiles are more or less deprecated. All the
bike profiles are generated from slight variations from a base profile,
and the latest and more up to date version can be found by manually
building <a href="https://github.com/poutnikl/Trekking-Poutnik">from the dedicated
repository</a>. Descriptions
of the available profiles for bikes is available in <a href="https://github.com/poutnikl/Trekking-Poutnik/wiki">the
wiki</a>.</li>
<li><a href="https://github.com/utack/utack_brouter_data/blob/master/streetbike_touring.brf">streetbike_touring
profile</a>
which is more aimed at city routing.</li>
<li>For velomobile, BRouter offers one profile in its repository and there is
another one available at
<a href="https://github.com/ThomasTraber/brouter_profiles_and_testing/blob/master/velomobil-tt.brf">https://github.com/ThomasTraber/brouter_profiles_and_testing/blob/master/velomobil-tt.brf</a>
and a last one in <a href="https://github.com/abrensch/brouter/pull/103">a <span class="caps">PR</span></a>.</li>
</ul>
<p><em>Note:</em> I mainly focus on regular bike profiles here. I am not really
interested into car routing (the best results for BRouter seems to be given
with the car profiles using the kinematic model but I have no idea how this
compares to <a href="http://project-osrm.org/"><span class="caps">OSRM</span></a> or other routing engine). I never
rode a <a href="https://en.wikipedia.org/wiki/Velomobile">velomobile</a>, so I don’t
really know which profiles are better fits for these.</p>
<p>Customizable profiles are a great strength of BRouter but the number of
available profiles is quickly misleading. It is also easy to start developping
profiles for everything, having profiles for each particular use case or
weather condition. Then, it is quite difficult to find which are the best
profiles out there.</p>
<p>Having played a bit with a number of profiles, I really think only a handful
of profiles should be kept for normal use and they can match with a lot of
different situations. I would personnally keep (as on my instance):</p>
<ul>
<li><code>misc/profiles2/trekking.brf</code>, the default “trekking” profile for general
bike routing, be for routing in the city or for holidays in the country
side / along cycle routes. This is really a wide use case profile.</li>
<li><span class="dquo">“</span>safety” profile (as on the <a href="http://brouter.de/brouter-web/">brouter.de</a>
website) which is actually the same profile as the “trekking” one with
<a href="https://github.com/abrensch/brouter/blob/6d95bc46e7e6da12a20f40b98be9d304ba4d29b3/misc/profiles2/trekking.brf#L16"><code>avoid_unsafe</code></a>
set to <code>true</code> to avoid routes without cycle ways.</li>
<li><code>misc/profiles2/fastbike.brf</code> (with <a href="https://github.com/abrensch/brouter/pull/58">this
<span class="caps">PR</span></a>) for speed (often coming
with unsafe ways), typically if you want to go fast from one point to
another or if you are sportive on your road bike.</li>
</ul>
<p><em>Note:</em> The “trekking” profile, although being one of the best one around has
some drawbacks, which I tried to fix in the “phyks-trekking” (and
“phyks-safety”) profiles on <a href="http://brouter.phyks.me/">my instance</a>. This is
still a Work In Progress and there will be another article about profile creation.</p>
<h2>BRouter web interface</h2>
<p>The official instance at <a href="http://brouter.de/brouter-web/">brouter.de</a> has a
modern web frontend. This frontend is <span class="caps">FOSS</span> as well and the code is available
at
<a href="https://github.com/nrenner/brouter-web">https://github.com/nrenner/brouter-web</a>
(and the <span class="caps">README</span> is well documented).
We will see how to add it in front of our BRouter server.</p>
<p>First, let us clone the BRouter-web git repository:</p>
<div class="highlight"><pre><span></span><code>git clone https://github.com/nrenner/brouter-web
</code></pre></div>
<p>Then, if we don’t have <code>bower</code> and <code>gulp</code>, we can run <code>npm install</code> to install
them locally. Otherwise, you can skip this step and use the system wide
binaries instead of the local ones. Then, we can install the required <span class="caps">JS</span> dependencies</p>
<div class="highlight"><pre><span></span><code>./node_modules/.bin/bower install
</code></pre></div>
<p>and finally we can build the code for production</p>
<div class="highlight"><pre><span></span><code>./node_modules/.bin/gulp
</code></pre></div>
<p>We will then configure the frontend:</p>
<div class="highlight"><pre><span></span><code>cp config.template.js config.js
$EDITOR config.js
</code></pre></div>
<p>We can configure the <a href="https://github.com/nrenner/brouter-web/blob/5751792b4924d62ff95bf80d2f4afee2e2950287/config.template.js#L47-L58">available
profiles</a>
(listed in the frontend) and the <a href="https://github.com/nrenner/brouter-web/blob/5751792b4924d62ff95bf80d2f4afee2e2950287/config.template.js#L60">BRouter server <span class="caps">URL</span> and
port</a>.</p>
<p>We will then configure the keys used by the frontend:</p>
<div class="highlight"><pre><span></span><code>cp keys.template.js keys.js
$EDITOR keys.js
</code></pre></div>
<p>There is no need to fill-in the <span class="caps">API</span> keys in this file, it only depends on the
features of the frontend you want to use. For instance, if you want to remove
the “<span class="caps">API</span> key required” watermark on the OpenCycleMap background, create a key
<a href="https://thunderforest.com/pricing/">for Thunderforest</a>.</p>
<p><em>Note:</em> There is no need to rebuild the app (running <code>gulp</code>) when you edit the
configuration or the keys.</p>
<p>The <code>brouter-web</code> repository can then be served directly with your <span class="caps">HTTP</span>
server (or you can use <code>python3 -m http.server</code> to spawn a webserver serving
this content). Head to your web server with your browser
(<code>http://localhost:8000</code> if you use <code>python3 -m http.server</code>) and enjoy your
new working BRouter instance!</p>
<p><strong><span class="caps">EDIT</span></strong>: An alternative interface, with a much more modern look and feel (but
fewer advanced features) is
<a href="https://github.com/mekto/brouter-online">brouter-online</a>. It seems to no
longer be maintained, but a fork with updated dependencies and compatibility
with latest BRouter server code is available
<a href="https://github.com/phyks/brouter-online">here</a>. Pull requests are more than
welcome on this one! :)</p>Et si on allait jusqu’à Stockholm en train ?2018-10-30T21:12:00+01:002018-10-30T21:12:00+01:00Phykstag:localhost,2018-10-30:/Blog/output/2018/10/et-si-on-allait-jusqua-stockholm-en-train.html<p>Lorsque j’ai découvert que le train entre Hambourg et Copenhague embarquait
sur un ferry au milieu du trajet, il fallait que je fasse ce trajet ! Et puis,
tant qu’à faire, pourquoi ne pas partir de Paris et aller jusqu’à Stockholm ?
Un peu plus de 2000 km en train, parcourus en 12 jours avec des étapes à
Bruxelles, Cologne, Hambourg, Copenhague, Malmö, Göteborg et enfin Stockholm,
le terminus. C’est parti !</p>
<p>Lorsque j’ai découvert que le train entre Hambourg et Copenhague embarquait
sur un ferry au milieu du trajet, il fallait que je fasse ce trajet ! Et puis,
tant qu’à faire, pourquoi ne pas partir de Paris et aller jusqu’à Stockholm ?
Un peu plus de 2000 km en train, parcourus en 12 jours avec des étapes à
Bruxelles, Cologne, Hambourg, Copenhague, Malmö, Göteborg et enfin Stockholm,
le terminus. C’est parti !</p>
<p>Le bon côté en partant fin septembre, c’est qu’il fait encore assez beau, tout
en étant hors saison donc il y a moins de monde et il y a des tarifs réduits
dans pas mal d’endroits. Attention cependant, de nombreux sites ferment hors
saison et les autres ont des horaires réduits.</p>
<p>Les prix sont donnés à titre indicatif. On avait pris tous les billets à peu
près 2 mois en avance. Pour les couronnes danoises, le taux de change est
d’environ 1 € = 7 <span class="caps">DK</span>. Pour les couronnes suédoises, le taux de change est
d’environ 1 € = 10 <span class="caps">SEK</span>.</p>
<h2>1er jour, Bruxelles et Brugge</h2>
<p>Le premier jour, on part de Paris en Thalys, direction Bruxelles (départ à
7h25 de Paris, arrivée à 8h47, 29 € par personne en tarif “Mini”).</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j1/DSC07351.JPG" title="Le Thalys">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j1_mini/DSC07351.JPG"
style="max-width: 50%"
alt="Le Thalys" />
</a>
</p>
<p><strong>Note</strong> : Attention aux billets Bruxelles → Paris achetés par la <span class="caps">SNCF</span>, pas
moyen de les imprimer en gare de Bruxelles, sauf à payer 15 €. Mieux vaut passer
directement par le site <a href="https://www.thalys.com/fr/fr/">Thalys</a> ou
<a href="http://trainline.eu/">Trainline</a>.</p>
<p>Comme on connaissait déjà Bruxelles, on a décidé d’aller à Brugge (Bruges en
français). Il y a plusieurs trains par heure (notamment sur <a href="http://www.belgianrail.be/fr/service-clientele/outils-voyage/~/media/B47DA7B888224B87BF23077BD3D26D59.pdf">la ligne
Bruxelles - Gent - Brugge -
Oostende</a>).
Les billets peuvent s’acheter en avance <a href="https://www.belgiantrain.be/fr/search">en
ligne</a> ou aux bornes à la gare. Si vous
êtes jeunes (moins de 26 ans), le plus rentable est de prendre des billets <a href="https://www.belgiantrain.be/fr/tickets-and-railcards/gopass1">“Go
Pass 1”</a> qui
vous coûteront 6,4 € par trajet, quelque soit la distance parcourue en
Belgique. Si vous utilisez les dix trajets (ou si vous retournez en Belgique
dans l’année), les
<a href="http://www.belgianrail.be/fr/billets-abonnements/age/adults-seniors/now-and-then/rail-pass.aspx">RailPass</a>
permettent de voyager sur tout le territoire belge pour 7,7 € par trajet
(plusieurs personnes peuvent voyager avec le même RailPass, ça décompte
simplement un trajet par personne). Enfin, il existe des billets Thalys <span class="caps">TGB</span>
(Toutes Gares Belges) qui sont un peu plus cher mais permettent de faire une
correspondance avec un train belge à l’arrivée à Bruxelles, sans supplément.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j1/DSC07354.JPG" title="Le train Bruxelles - Gent - Brugge">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j1_mini/DSC07354.JPG"
style="max-width: 50%"
alt="Le train Bruxelles - Gent - Brugge" />
</a>
</p>
<p><strong>Note</strong> : À la gare de Bruxelles Midi, les WCs sont payants (0.6 €) et il y a des
consignes de différentes tailles. Les plus petites, qui peuvent stocker deux
bagages format “cabine” sans problèmes, sont à 5 € la journée, à payer en
espèces uniquement. Aussi, en Belgique on trouve peu de fontaines d’eau
potable dans les rues, et l’eau est en général payante dans les restaurants.</p>
<h3>Brugge</h3>
<p>On a donc décidé de passer la journée à Brugge. Voici <a href="https://maps.openrouteservice.org/directions?n1=51.205089&n2=3.225936&n3=16&a=51.196867,3.217213,51.203623,3.222352,51.204632,3.224434,51.205673,3.221226,51.207831,3.225099,51.208544,3.224455,51.208718,3.226805,51.208154,3.227148,51.207999,3.22673,51.213829,3.239084,51.201452,3.223425,51.199468,3.22453,51.196961,3.217106&b=2&c=0&g1=-1&g2=0&k1=en-US&k2=km">un petit
itinéraire</a>
avec les principaux sites touristiques.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j1/DSC07365.JPG"
title="Brugge">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j1_mini/DSC07365.JPG"
style="max-width: 24%"
alt="Brugge" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j1/DSC07383.JPG" title="Une baleine de plastique à Brugge">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j1_mini/DSC07383.JPG"
style="max-width: 24%"
alt="Une baleine de plastique à Brugge" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j1/DSC07389.JPG"
title="Les moulins de Brugge">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j1_mini/DSC07389.JPG"
style="max-width: 24%"
alt="Les moulins de Brugge" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j1/DSC07394.JPG"
title="Une façade amusante !">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j1_mini/DSC07394.JPG"
style="max-width: 24%"
alt="Une façade amusante !" />
</a>
</p>
<p>Quelques adresses à Bruges :</p>
<ul>
<li><a href="https://www.openstreetmap.org/node/4827054559">Chez Albert</a>, un stand de
gaufres, visiblement un des meilleurs de la ville. Un monde fou et à
emporter uniquement, on n’a pas testé du coup…</li>
<li><a href="https://www.openstreetmap.org/node/5970448654">Salé et Sucré</a>, un petit
café très sympa qui fait d’excellentes gaufres aussi.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j1/DSC07397.JPG" title="Les gaufres de Salé et Sucré">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j1_mini/DSC07397.JPG"
style="max-width: 50%"
alt="Les gaufres de Salé et Sucré" />
</a>
</p>
<ul>
<li>Pour les chocolats, il y a <a href="https://www.openstreetmap.org/node/1187809495">The Chocolate
Line</a>, très cher, mais le
magasin et sa déco est à voir !</li>
<li>Pour les chocolats, beaucoup plus abordable, il y a
<a href="https://www.openstreetmap.org/way/416217531">Dumon</a> qui est très bon
aussi. Plusieurs adresses à Brugge,
<a href="https://www.openstreetmap.org/node/1187756874">ici</a> aussi par exemple.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j1/DSC07414.JPG" title="Godshuis de Vos">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j1_mini/DSC07414.JPG"
style="max-width: 30%"
alt="Godshuis de Vos" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j1/DSC07419.JPG"
title="Le béguinage de Brugge">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j1_mini/DSC07419.JPG"
style="max-width: 30%"
alt="Le béguinage de Brugge" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j1/DSC07421.JPG">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j1_mini/DSC07421.JPG"
style="max-width: 30%"
alt="Minnewater" />
</a>
</p>
<p>Quelques liens pratiques sur Brugge:</p>
<ul>
<li><a href="http://alittlepieceof.fr/adresses-bruges/">http://alittlepieceof.fr/adresses-bruges/</a></li>
</ul>
<h3>Bruxelles</h3>
<p>Le soir, retour à Bruxelles d’où nous repartons le lendemain matin. On a passé
la nuit dans un Airbnb à côté de
<a href="https://www.openstreetmap.org/node/144070391">Saint-Guidon</a>, sur les bords du
canal. Le quartier est moitié résidentiel, moitié zone
industrialo-commerciale mais le métro à Saint-Guidon permet de rejoindre le
centre-ville assez facilement (compter 30 minutes). Il y a un bus direct qui
rejoint la gare de Bruxelles midi en 10 minutes (compter 30 minutes de marche
peu agréable à pied sinon). Le bon plan reste les
<a href="http://www.villo.be/">Villo</a> (les mêmes que les Vélib 1) qui vous permettent
de rejoindre le centre de Bruxelles en 15 minutes avec une piste cyclable très
agréable le long du canal (séparée de la circulation motorisée). Un ticket 24h
pour le Villo coûte 1,6 € et vous permet de prendre autant de vélos que vous
voulez pendant les 24h sous réserve que chaque vélo soit gardé moins de 30
minutes (sinon, il faut payer un petit supplément).</p>
<p>Quelques adresses à Bruxelles :</p>
<ul>
<li><a href="https://www.openstreetmap.org/node/3328732612">Le Fin de Siècle</a> (merci
<a href="https://framapiaf.org/@ZeHiro">ZeHiro</a> pour l’adresse !), un restaurant
bon et copieux avec de la cuisine régionale, pas très cher et avec des
options végétariennes. Attention, paiement en espèces uniquement !</li>
<li><a href="https://www.openstreetmap.org/way/306856244">Le Delirium Café</a>
(merci <a href="https://tutut.delire.party/@bnjbvr">bnjbvr</a> pour l’adresse !), un
bon bar très touristique avec une longue carte et de bonnes bières
(l’étage est plus calme).</li>
<li><a href="https://www.openstreetmap.org/way/244956151">Le bar O’Reilly’s</a> devant la bourse.</li>
<li><a href="https://www.openstreetmap.org/node/4413952472">Goupil le Fol</a> (merci
<a href="https://framapiaf.org/@ZeHiro">ZeHiro</a> pour l’adresse !), un bar très
sympa sur le thème de la chanson française. Une description en quelques
mots ne serait pas très juste et ne pourrait rendre compte de l’ambiance
de ce bar, à tester ! :)</li>
</ul>
<h2>2e jour : Cologne et Hambourg</h2>
<p>Deux trajets en train pour ce deuxième jour :</p>
<ul>
<li>Un <span class="caps">DB</span> <span class="caps">ICE</span> de Bruxelles à Cologne (départ 8h23, arrivée 10h15), 15 € par personne.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j2/DSC07428.JPG" title="Le DB ICE Bruxelles - Cologne">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j2_mini/DSC07428.JPG"
style="max-width: 50%"
alt="Le DB ICE Bruxelles - Cologne" />
</a>
</p>
<ul>
<li>Un <span class="caps">DB</span> <span class="caps">IC</span> de Cologne à Hambourg (départ 14h10, arrivée à 18h14), 30 € par personne.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j2/DSC07479.JPG" title="Le DB IC Cologne - Hambourg">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j2_mini/DSC07479.JPG"
style="max-width: 50%"
alt="Le DB IC Cologne - Hambourg" />
</a>
</p>
<p>Ces trajets nous laissent 4h à Cologne, largement de quoi découvrir <a href="https://fr.wikipedia.org/wiki/Cath%C3%A9drale_de_Cologne">la
cathédrale</a> et
explorer le centre historique !</p>
<p><strong>Note</strong> : Attention aux partenaires de la <span class="caps">DB</span> (Trainline par exemple). La <span class="caps">DB</span> ne
les notifie pas en cas de changement sur votre train et la <span class="caps">DB</span> ne notifie
directement que les clients ayant acheté chez eux. Il faut donc vérifier
soi-même que le train n’a pas été modifié avant le départ, si vous avez acheté
chez un partenaire. C’est probablement plus pratique d’acheter directement
auprès de la <span class="caps">DB</span> du coup…</p>
<p><strong>Note</strong> : Sur tous les trajets en train qu’on a fait, on n’a eu qu’un seul
retard, de 30 minutes, sur le train entre Bruxelles et Cologne. Visiblement
(selon les témoignages en ligne), la <span class="caps">DB</span> est une habituée des retards…
Attention à ne pas prendre une correspondance trop courte à Cologne du coup !</p>
<p><strong>Note</strong> : Attention, dans les trains de la <span class="caps">DB</span>, en seconde, la réservation (une
place assise réservée) n’est pas incluse et il faut payer un supplément si on
le veut (c’est gratuit en première). Ce n’est en général pas un problème de ne
pas la prendre, il y a toujours des places libres (sur les trajets qu’on a
fait c’était le cas en tout cas), mais il faut potentiellement se déplacer en
cours de trajet. Sur nos trajets, tous les sièges avaient toujours un écran
qui clignotait “attention, ce siège peut être réservé”, sans donner plus
d’informations… pas très pratique pour savoir où s’asseoir !</p>
<h3>Cologne</h3>
<p>À la gare de Cologne, il y a deux consignes automatiques (3 € pour 2h, 6 € par
24h, maximum 72h pour un petit casier comme celui de Bruxelles). On peut payer
en espèces, en carte (mais tous les boîtiers carte étaient <span class="caps">HS</span>) ou en billets.
Parfait pour laisser ses affaires et aller visiter la cathédrale !</p>
<p>Voici <a href="https://maps.openrouteservice.org/directions?n1=50.940129&n2=6.951481&n3=16&a=50.942719,6.959034,50.941306,6.958326,50.938689,6.958777,50.937911,6.959848,50.939379,6.954743,50.935951,6.947629,50.934626,6.958562,50.936742,6.960644,50.93804,6.9631,50.93852,6.961609,50.943266,6.945033,50.942651,6.959066&b=2&c=0&g1=-1&g2=0&k1=en-US&k2=km">un petit
itinéraire</a>
pour faire un tour à Cologne.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j2/DSC07439.JPG" title="La cathédrale de Cologne">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j2_mini/DSC07439.JPG"
style="max-width: 30%; max-height: 300px;"
alt="La cathédrale de Cologne" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j2/DSC07447.JPG" title="Une maison à colombages">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j2_mini/DSC07447.JPG"
style="max-width: 30%; max-height: 300px;"
alt="Une maison à colombages" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j2/DSC07446.JPG" title="La Rathausturm">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j2_mini/DSC07446.JPG"
style="max-width: 30%; max-height: 300px;"
alt="La Rathausturm" />
</a>
</p>
<p>Pour manger, on a trouvé <a href="https://www.openstreetmap.org/node/3159374271">un
stand</a> de <a href="https://fr.wikipedia.org/wiki/Currywurst">curry
wurst</a>. Attention, on a eu beaucoup
de mal à trouver un supermarché à Cologne, dans le centre-ville. Il y a par
contre un petit <a href="https://www.openstreetmap.org/way/504626590"><span class="caps">REWE</span> à la gare</a>,
avec des tarifs étonnamment raisonnables pour une gare.</p>
<p>Quelques liens utiles :</p>
<ul>
<li><a href="http://comme-un-poisson-dans-leau.fr/que-faire-cologne-2-jours/">http://comme-un-poisson-dans-leau.fr/que-faire-cologne-2-jours/</a></li>
<li><a href="http://comme-un-poisson-dans-leau.fr/manger-cologne-pas-cher-adresses/">http://comme-un-poisson-dans-leau.fr/manger-cologne-pas-cher-adresses/</a></li>
</ul>
<h3>Hambourg</h3>
<p>Un itinéraire pour faire un tour à Hambourg est visible
<a href="https://maps.openrouteservice.org/directions?n1=53.547148&n2=9.976562&n3=16&a=53.545006,9.95327,53.545669,9.966627,53.548353,9.978912,53.541276,9.984319,53.54616,10.003438,53.550329,10.000767,53.550322,9.996668,53.550507,9.992559,53.54936,9.986604,53.558379,9.996454,53.558863,9.964406&b=2&c=0&g1=-1&g2=0&k1=en-US&k2=km">ici</a>,
en commençant par les quais et les vues sur les grues du port industriel en
face, puis en passant dans la
<a href="https://fr.wikipedia.org/wiki/Speicherstadt">Speicherstadt</a>, une ancienne
zone d’entrepôts classée à l’<span class="caps">UNESCO</span> et aujourd’hui reconvertie, puis en
continuant dans le centre-ville et le long des canaux avant de finir sur les
bords du lac Alster et dans le quartier qui bouge, vers Sternchanze.</p>
<p>Pour se déplacer dans Hambourg, le plus simple est probablement de prendre les
transports en commun (S-Bahn, comme le <span class="caps">RER</span>, ou le U-Bahn, comme le métro). On
peut acheter des tickets “courts trajets” aux bornes (1.6 € / ticket), qui sont
valables pour 3 stations maximum. Attention, le ticket est valable pour une
durée limitée (1h30 de mémoire) et la période démarre immédiatement après
l’achat ! Pas besoin de composter du coup, mais on ne peut pas en acheter en
avance en prévision.</p>
<p>Pour manger le soir, on a testé (et approuvé !)
<a href="https://www.openstreetmap.org/node/280709543">Hatari</a>, une brasserie (burgers
etc) vraiment bien, avec même des super options végétariennes ! Pour loger, on
était à côté de la station
<a href="https://www.openstreetmap.org/node/52144750">Baumwall</a> et c’était super et
très bien situé.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j2/DSC07482.JPG" title="La gare de Hambourg">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j2_mini/DSC07482.JPG"
style="max-width: 45%"
alt="La gare de Hambourg" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j2/DSC07486.JPG" title="Les grues sur le port de Hambourg">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j2_mini/DSC07486.JPG"
style="max-width: 45%"
alt="Les grues sur le port de Hambourg" />
</a>
</p>
<p>Quelques liens utiles en vrac sur Hambourg :</p>
<ul>
<li><a href="http://www.allemagnevoyage.com/villes/Hambourg/hambourgmaritime.html">http://www.allemagnevoyage.com/villes/Hambourg/hambourgmaritime.html</a></li>
<li><a href="http://www.allemagnevoyage.com/villes/Hambourg/hambourgweekend.html">http://www.allemagnevoyage.com/villes/Hambourg/hambourgweekend.html</a></li>
<li><a href="https://www.carnets-de-traverse.com/blog/visiter-hambourg">https://www.carnets-de-traverse.com/blog/visiter-hambourg</a></li>
<li><a href="http://viedexpat.com/visiter-hambourg-que-faire-week-end/">http://viedexpat.com/visiter-hambourg-que-faire-week-end/</a></li>
</ul>
<h2>3e jour, Copenhague, du côté du centre-ville</h2>
<h3>Le train</h3>
<p>Pour ce troisième jour, direction Copenhague, par un train un peu particulier
(un <span class="caps">DB</span> <span class="caps">EC</span>) ! Départ de Hambourg à 9h28, arrivée à Copenhague à 14h26, compter
70 € par personne (le prix a bondi au moment où on a acheté, la veille il était
encore à 35 € par personne…).</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07496.JPG" title="Le train Hambourg - Copenhague">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07496.JPG"
style="max-width: 45%"
alt="Le train Hambourg - Copenhague" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07499.JPG" title="L'intérieur du train Hambourg - Copenhague">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07499.JPG"
style="max-width: 45%; max-height: 300px;"
alt="L'intérieur du train Hambourg - Copenhague" />
</a>
</p>
<p><strong>Note</strong> : Le train Hambourg - Copenhague est étonnamment court (quelques
voitures seulement) et donc forcément très rempli… On a réussi à trouver des
places libres pour le trajet, mais il est préférable de prendre une
réservation sur ce train pour être tranquille.</p>
<p>Au bout de quelques heures de rails, le train embarque… dans un ferry ! Et il
traverse ainsi entre
<a href="https://www.openstreetmap.org/node/3739434321">Puttgarden</a> et
<a href="https://www.openstreetmap.org/node/769861680">Rødby</a> (45 minutes de ferry).
C’est assez étonnant de voir un train emprunter un ferry (et c’était une des
motivations initiales du voyage !) ! C’est un des derniers trains à le faire
encore en Europe (et un tunnel est en projet pour supprimer cette étape). Du
coup, forcément, le train est raccourci au minimum, pour tenir dans le ferry.
Les services sont donc limités à bord et il n’y a pas de wagon bar par exemple
(simplement quelques distributeurs entre les voitures). Lors de la traversée
en ferry, le train est verrouillé (on peut donc laisser ses bagages en
sécurité) et les passagers doivent monter sur les ponts supérieurs du ferry.
Sur le ferry (comme sur tous les autres ferrys qu’on a pris), il y a le
classique magasin “duty free” ainsi que des cafés qui servent des sandwiches
et des saucisses-frites (à des tarifs danois…).</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07502.JPG" title="Le train dans le ferry">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07502.JPG"
style="max-width: 24%"
alt="Le train dans le ferry" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07506.JPG" title="Des pictogrammes surprenant dans un ferry">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07506.JPG"
style="max-width: 24%"
alt="Des pictogrammes surprenant dans un ferry" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07528.JPG" title="Au débarquement">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07528.JPG"
style="max-width: 24%"
alt="Au débarquement" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07505.JPG" title="Le ferry">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07505.JPG"
style="max-width: 24%"
alt="Le ferry" />
</a>
</p>
<p><strong>Note</strong> : Attention au hors-forfait sur le ferry, on passe sur un opérateur
“maritime” hors Danemark et Allemagne et gare à la facture !</p>
<p>À l’arrivée à la gare de Copenhague, il y a de nombreuses consignes entre 65
et 75 <span class="caps">DKK</span> pour 24h (selon la taille du casier). Attention, peu de consignes
acceptent le paiement par carte bancaire et ce sont celles qui sont utilisées
en priorité. Mieux vaut donc avoir quelques espèces pour être tranquille.</p>
<h3>Copenhague</h3>
<p>Pour visiter Copenhague, il existe la <a href="https://copenhagencard.com/">Copenhague
Card</a>, mais elle n’est pas forcément rentable si
vous êtes étudiants ou jeunes car vous avez déjà de nombreuses réductions dans
les musées.</p>
<p><strong>Note</strong> : Au Danemark, les musées ouvrent vers 10h et ferment tôt (entre 16h
et 18h pour la plupart). Pensez-y pour adapter votre itinéraire et votre
journée en conséquence :)</p>
<p>Un itinéraire pour faire un tour dans le centre historique de Copenhague est
disponible
<a href="https://maps.openrouteservice.org/directions?n1=55.675812&n2=12.57646&n3=16&a=55.67223,12.564508,55.675407,12.569904,55.676744,12.569979,55.679006,12.576985,55.678667,12.581599,55.680476,12.585944,55.679097,12.593862,55.678788,12.592789,55.676502,12.588626,55.676586,12.583627,55.67554,12.584023,55.673555,12.582961,55.675503,12.580419,55.676169,12.579045,55.675116,12.577307,55.68039,12.573226&b=2&c=0&g1=-1&g2=0&k1=en-US&k2=km">ici</a>.
On passe notamment :</p>
<ul>
<li>devant le <a href="https://www.openstreetmap.org/way/314752241">parc Tivoli</a>, un
grand parc d’attractions, malheureusement fermé à cette période de l’année
(il rouvre pour Halloween et Noël).</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07595.JPG" title="Tivoli">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07595.JPG"
style="max-width: 50%"
alt="Tivoli" />
</a>
</p>
<ul>
<li>à l’<a href="https://www.openstreetmap.org/relation/52142">Hôtel de Ville</a> qu’on
peut visiter librement. On peut aussi y admirer une très belle horloge,
dans une salle en entrant à droite (entrée gratuite car en rénovation
actuellement). Il y a de jolies façades sur cette place, dont celle du
Scandic Hotel.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07542.JPG" title="L'Hôtel de Ville">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07542.JPG"
style="max-width: 45%"
alt="L'Hôtel de Ville" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07552.JPG" title="Le grand hall de l'Hôtel de Ville">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07552.JPG"
style="max-width: 45%"
alt="Le grand hall de l'Hôtel de Ville" />
</a>
</p>
<ul>
<li>dans la rue piétonne Nygade qui traverse les places de
<a href="https://www.openstreetmap.org/way/25822563">Gammeltorv</a>,
<a href="https://www.openstreetmap.org/way/24739672">Nytorv</a> et
<a href="https://www.openstreetmap.org/way/24721845">Amagertorv</a>.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07560.JPG" title="Gråbrødretorv">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07560.JPG"
style="max-width: 50%"
alt="Gråbrødretorv" />
</a>
</p>
<ul>
<li>à côté de l’<a href="https://www.openstreetmap.org/way/133104582">église du
Saint-Esprit</a>.</li>
<li>au pied de la <a href="https://www.openstreetmap.org/way/25822596">tour Nikolaj</a>.</li>
<li>sur la place <a href="https://www.openstreetmap.org/node/1003298560">Kongens Nytorv</a>
avec de magnifiques bâtiments dont le théâtre et le château de
Charlottenborg. La place est en travaux en ce moment pour la construction
d’une nouvelle ligne de métro.</li>
<li>à <a href="https://www.openstreetmap.org/way/180380518">Nyhavn</a>, le petit quai carte
postale de Copenhague.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07569.JPG" title="Nyhavn">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07569.JPG"
style="max-width: 50%"
alt="Nyhavn" />
</a>
</p>
<ul>
<li>à l’<a href="https://www.openstreetmap.org/way/264362254">Holmens Kirke</a>, une
ancienne fabrique convertie en usine.</li>
<li>devant la <a href="https://www.openstreetmap.org/way/25466204">bourse</a> historique de
Copenhague, aujourd’hui une chambre de commerce (qui ne se visite pas). Le
bâtiment est surmonté d’une flèche avec quatre dragons dont les queues
entrelacées finissent en corne de narval et marque l’union indissoluble
des 4 royaumes des pays nordiques. Beaucoup de photos de la Bourse <a href="http://www.noblesseetroyautes.com/lancienne-bourse-de-copenhague-batie-sous-le-regne-de-christian-iv/">par
ici</a>.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07578.JPG" title="La bourse">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07578.JPG"
style="max-width: 50%"
alt="La bourse" />
</a>
</p>
<ul>
<li>à la nouvelle <a href="https://www.openstreetmap.org/relation/2682249">Bibliothèque
royale</a>, bâtiment ultra
moderne sur le quai qui intègre et se connecte aux bâtiments historiques.</li>
<li>au <a href="https://www.openstreetmap.org/way/25992657#map=18/55.67569/12.57907">château de
Christiansborg</a>,
aujourd’hui en partie le siège du Parlement danois. Ne pas rater le
<a href="https://www.openstreetmap.org/node/1446079691">“parking du parlement”</a>,
plus de 200 places de stationnements vélos, toutes utilisées, pour les
parlementaires !</li>
</ul>
<p>Il y a <a href="https://www.visitcopenhagen.com/copenhagen/tower-christiansborg-palace-gdk917422">une
tour</a>
de 106m de haut au château de Christiansborg (avec un ascenseur pour monter).
L’accès est gratuit et la vue superbe ! La tour est ouverte à des horaires
assez larges car il y a un restaurant à l’avant-dernier étage. Prévoir un peu
d’attente (15 minutes à 19h pour nous) avant de pouvoir monter.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j3/DSC07591.JPG" title="Vue sur Copenhague depuis le sommet">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j3_mini/DSC07591.JPG"
style="max-width: 50%"
alt="Vue sur Copenhague depuis le sommet" />
</a>
</p>
<p><strong>Note</strong> : Il y a de nombreux musées d’art à Copenhague aussi, dont le <a href="https://www.openstreetmap.org/relation/1989714#map=19/55.67471/12.57480">Musée
national du
Danemark</a>
ou la <a href="https://www.openstreetmap.org/relation/1322262">Ny Carlsberg Glyptotek</a>
(du nom de la célèbre brasserie locale). À vous de voir en fonction de vos
intérêts et du temps disponible :)</p>
<p>Le soir, on a mangé au <a href="https://www.openstreetmap.org/node/894404556">Paludan
Café</a>, un mix de café,
restaurant (et librairie ?) très sympa (et très étudiant). En rentrant, on
s’installe sur une table au milieu des rayons de livres puis il faut aller
commander au bar. Prix raisonnables (mais danois quand même) et options
végétariennes !</p>
<p>En voulant rentrer à notre logement le soir, on a découvert… le bus à
Copenhague… ou plutôt l’épreuve du combattant pour trouver où acheter son
ticket de bus ! Dans la gare de Copenhague, il y a pas plein de distributeurs
différents : les distributeurs de la <span class="caps">DSB</span> (la <span class="caps">SNCF</span> danoise), les distributeurs
de <span class="caps">SJ</span> (la <span class="caps">SNCF</span> suédoise), les distributeurs pour les trains qui traversent
vers la Suède, … Aucun n’est clairement assigné pour les transports en commun
de Copenhague, mais il semblerait que ce soit la borne de la <span class="caps">DSB</span> qui vende ces
billets. Il faut ensuite trouver le bon billet (on essaye au hasard, en
vérifiant si le prix correspond au prix attendu), puis la carte de crédit est
refusée par la machine (qui ne prend visiblement aucune carte de crédit française…).</p>
<p>Bref, pour acheter un billet de bus (24 <span class="caps">DKK</span> pour un trajet), le plus simple
est de le prendre directement auprès du conducteur. Attention, il n’accepte
que les petites coupures (100 <span class="caps">DKK</span> grand maximum) !</p>
<h2>4e jour, Copenhague, du côté de Nørrebro et Amalienborg</h2>
<p>Pour démarrer la journée, on est allé faire un tour dans
<a href="https://www.openstreetmap.org/node/21701704#map=15/55.6930/12.5561&layers=N">Nørrebro</a>,
le quartier hipster de Copenhague, surtout autour de <a href="https://www.openstreetmap.org/way/1911064#map=17/55.69272/12.54395&layers=N">Jægersborggade
</a>,
<a href="https://www.openstreetmap.org/way/162845131">Nørrebrogade</a> et
<a href="https://www.openstreetmap.org/way/4288832">Elmegade</a>. C’est aussi l’occasion
de faire un tour dans le cimetière <a href="https://www.openstreetmap.org/way/3099111#map=16/55.6908/12.5496&layers=N">Assistens
Kirkegård</a>
où sont notamment enterrés <a href="https://www.openstreetmap.org/node/477438328">Hans Christian
Andersen</a> (des comptes), <a href="https://www.openstreetmap.org/node/1286495201">Niels
Bohr</a> (de la physique
quantique) et de <a href="https://www.openstreetmap.org/node/293234123">Søren Aabye
Kierkegaard</a> (le philosophe).</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j4/DSC07599.JPG" title="La tombe de Niels Bohr">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j4_mini/DSC07599.JPG"
style="max-width: 50%"
alt="La tombe de Niels Bohr" />
</a>
</p>
<p>À deux pas de là, on recommande <a href="https://www.openstreetmap.org/node/335962988">The Coffee
Collective</a> pour un (très) bon
café (et chocolat chaud) ! C’est aussi un très bon endroit pour se poser à
proximité de prises électriques pour déballer cartes et ordis et planifier le
reste de la journée :) On ne manquera pas en chemin la <a href="https://www.openstreetmap.org/node/1210423311">boulangerie
Meyers</a> et ses excellentes
pâtisseries !</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j4/DSC07601.JPG" title="The Coffee Collective">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j4_mini/DSC07601.JPG"
style="max-width: 30%"
alt="The Coffee Collective" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j4/DSC07603.JPG" title="Spandauer, brioche à la crème">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j4_mini/DSC07603.JPG"
style="max-width: 30%"
alt="Spandauer, brioche à la crème" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j4/DSC07604.JPG" title="Brioche à la canelle">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j4_mini/DSC07604.JPG"
style="max-width: 30%"
alt="Brioche à la canelle" />
</a>
</p>
<p>Pour manger un weekend, le brunch au <a href="https://www.openstreetmap.org/node/5996260578">Ravnsborg Kitchen <span class="amp">&</span>
Bar</a> est une très bonne option.
Pas mal de choix, un menu en anglais et des options végétariennes. Le service
est très lent par contre. Pour le brunch, le café propose une liste de petits
plats et on paye 59, 99, 139 <span class="caps">DKK</span> selon que l’on prenne 3, 5 ou 7 plats. Il y a
pas mal de choix et les portions sont raisonnables (surtout si l’on sort de la
boulangerie Meyers ! :p).</p>
<p>L’après-midi, direction
<a href="https://www.openstreetmap.org/way/378106484#map=15/55.6853/12.5856&layers=N">Amalienborg</a>,
le palais qui est la résidence d’hiver de la famille royale de Danemark. En
chemin, c’est l’occasion de voir :</p>
<ul>
<li>Le <a href="https://www.openstreetmap.org/way/25451395#map=19/55.68873/12.57837&layers=N">Statens Museum for Kunst</a></li>
<li>Le <a href="https://www.openstreetmap.org/way/3098803#map=16/55.6869/12.5740&layers=N">Botanisk
Have</a>
en face et les jolies <a href="https://www.openstreetmap.org/way/264570191">serres de la
palmeraie</a> (entrée des serres
à 60 <span class="caps">DKK</span>, 40 <span class="caps">DKK</span> pour les étudiants)</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j4/DSC07614.JPG" title="La palmeraie">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j4_mini/DSC07614.JPG"
style="max-width: 50%"
alt="La palmeraie" />
</a>
</p>
<ul>
<li>Le <a href="https://www.openstreetmap.org/way/25524592">Rosenborg Slot</a>, un très
joli château. L’entrée est à 110 <span class="caps">DKK</span> (75 <span class="caps">DKK</span> pour les étudiants). Il y a
une brochure complète en français. Ne pas manquer le trésor, au sous-sol,
où sont conservées les joyaux de la couronne danoise !</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j4/DSC07621.JPG" title="Le Rosenborg Slot">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j4_mini/DSC07621.JPG"
style="max-width: 45%; max-height: 300px;"
alt="Le Rosenborg Slot" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j4/DSC07635.JPG" title="Les joyaux de la couronne">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j4_mini/DSC07635.JPG"
style="max-width: 45%"
alt="Les joyaux de la couronne" />
</a>
</p>
<ul>
<li>L’impressionnante <a href="https://www.openstreetmap.org/way/25524833">Marmorkirken</a>
(en marbre) et la <a href="https://www.openstreetmap.org/way/55601707">petite église
orthodoxe</a> voisine.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j4/DSC07645.JPG" title="Marmorkirken">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j4_mini/DSC07645.JPG"
style="max-width: 50%"
alt="Marmorkirken" />
</a>
</p>
<ul>
<li>Le <a href="https://www.openstreetmap.org/relation/5693118">musée du design</a> dont
l’entrée est gratuite pour les étudiants et moins de 26 ans. Sinon, c’est
115 <span class="caps">DKK</span>, ce qui est un peu cher à mon avis. Il y a plusieurs expos : une
première salle sur les inspirations japonaises du design danois (pas mal),
puis plusieurs salles de collections de textiles et porcelaines (à passer
rapidement, sauf si vous aimez particulièrement ça) et les dernières
salles se concentrent sur le design contemporain. Cette dernière partie
est la plus intéressante, avec de nombreux meubles, chaises etc de grands designers.</li>
<li>Finalement, on arrive sur le château
d’<a href="https://www.openstreetmap.org/way/378106484">Amalienborg</a> et sa place,
d’où l’on a la perspective sur Marmorkirken d’une part et sur <a href="https://www.openstreetmap.org/way/25607878">le nouvel
opéra</a> d’autre part.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j4/DSC07656.JPG" title="Amalienborg">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j4_mini/DSC07656.JPG"
style="max-width: 50%"
alt="Amalienborg" />
</a>
</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Nyboder">Nyboder</a>, autour de
<a href="https://www.openstreetmap.org/way/1880908">Haregade</a> avec ses jolies
petites maisons oranges, initialement construites par Christian <span class="caps">IV</span> pour
loger le personnel de la marine et leurs familles.</li>
</ul>
<p>Finalement, on a fini la journée par remonter le long des quais jusqu’au
<a href="https://www.openstreetmap.org/way/175208408#map=16/55.6914/12.5943">Kastellet</a>,
une ancienne citadelle ouverte au public puis à la <a href="https://www.openstreetmap.org/node/25074274">statue de la
Petite-Sirène</a> qui est très
décevante (mais on avait été prévenu). Elle n’est pas très grande, noyée sous
les touristes (quoique hors saison et en fin de soirée, c’est probablement
plus raisonnable) et a de magnifiques éoliennes et cheminées d’usines en fond
(qu’on ne voit jamais sur les cartes postales :)).</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j4/DSC07678.JPG" title="La Petite Sirène comme vous ne l'avez jamais vue !">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j4_mini/DSC07678.JPG"
style="max-width: 50%"
alt="La Petite Sirène comme vous ne l'avez jamais vue !" />
</a>
</p>
<h2>5e jour, Copenhague du côté de Christianshavn et Christiana et Malmö</h2>
<h3>Copenhague du côté de Christianshavn et Christiana</h3>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j5/DSC07687.JPG" title="Christianshavn">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j5_mini/DSC07687.JPG"
style="max-width: 50%"
alt="Christianshavn" />
</a>
</p>
<p>Le lendemain matin, départ pour
<a href="https://www.openstreetmap.org/node/21697413#map=16/55.6729/12.5886">Christianshavn</a>,
sur l’île opposée au centre historique. C’est un ancien quartier de
manufactures (avec de grands et beaux bâtiments en briques :), avec des canaux
prévus pour décharger les marchandises directement des bateaux dans les
manufactures. Il ne faut pas rater :</p>
<ul>
<li>La <a href="https://www.openstreetmap.org/way/40106991">Christians Kirke</a> qui est
parait-il très jolie mais les horaires ont l’air assez aléatoires (et la
visite est interdite pendant les offices).</li>
<li>La <a href="https://www.openstreetmap.org/way/338137146">passerelle piétons/vélos</a>
dessinée par <a href="https://fr.wikipedia.org/wiki/Olafur_Eliasson">Olafur
Eliasson</a> et qui ressemble
à <a href="https://www.dezeen.com/2015/08/22/copenhagen-denmark-cirkelbroen-circle-bridge-olafur-eliasson-ship-masts/">des mâts de
bateaux</a>.</li>
<li>Ne surtout pas manquer la <a href="https://www.openstreetmap.org/way/25607908">Vor Frelsers
Kirke</a>, sauf si vous avez le
vertige peut-être… On peut monter tout en haut de la flèche de l’église
(90m de haut quand même !) et avoir une vue imprenable sur Copenhague.
Attention, l’ascension commence avec des escaliers assez raides en bois
pour monter dans le clocher puis un <a href="https://fr.wikipedia.org/wiki/%C3%89glise_de_Notre-Sauveur">escalier en colimaçon
extérieur</a>.
Prévoir un petit peu d’attente avant de pouvoir monter, selon la
fréquentation. L’ascension coûte 35 <span class="caps">DKK</span> (25 <span class="caps">DKK</span> pour les étudiants et les
moins de 25 ans).</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j5/DSC07688.JPG" title="Vor Frelsers Kirke">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j5_mini/DSC07688.JPG"
style="max-width: 45%"
alt="Vor Frelsers Kirke" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j5/DSC07695.JPG" title="Vor Frelsers Kirke">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j5_mini/DSC07695.JPG"
style="max-width: 45%"
alt="Vor Frelsers Kirke" />
</a>
</p>
<ul>
<li><a href="https://www.openstreetmap.org/way/250989045#map=16/55.6758/12.6038">La commune libre de
Christiana</a>,
une communauté autogérée de Copenhague, fondée sur le terrain d’une
ancienne caserne désaffectée en 1971 et qui tient bon (voir la <a href="https://fr.wikipedia.org/wiki/Christiania_(Danemark)">page
Wikipédia</a> pour plus
de détails sur son histoire et ses valeurs). La vente de cannabis (ielles
se positionnent en faveur d’une légalisation, bien que ce soit illégal au
Danemark) y est pratiquée mais toute vente ou consommation de drogues
dures est sévèrement réprimée. Attention, il est interdit de prendre des
photos dans les rues les plus proches de l’entrée, là où du cannabis est
vendu (des panneaux le signalent et on vous rappellera à l’ordre si vous
contrevenez). Dans le reste de la commune, on peut prendre des photos mais
il est nécessaire de demander l’accord des habitants avant de les prendre
ou leurs maisons en photos. Il n’y a pas grand chose à voir en pratique,
c’est un peu comme visiter une <span class="caps">ZAD</span>. C’est plutôt l’atmosphère et
l’organisation de la société qui valent le coup. Il y a quelques <a href="https://fr.wikipedia.org/wiki/Christiania_(Danemark)#/media/File:Christiania_-_Banana_House.jpg">très
jolies
maisons</a>
construites par les habitants, principalement au bord de l’eau. C’est
aussi là-bas que se trouvent les ateliers des <a href="https://www.christianiabikes.com/">Christiana
Bikes</a>, les triporteurs qu’on voit
partout à Copenhague ! On y est allé un dimanche matin donc l’ambiance
était très calme et très familial. Il y a des concerts et des animations
organisées en soirée. Bref, quoiqu’on en pense, il faut l’avoir vu au
moins une fois et ça vaut le coup !</li>
</ul>
<p>Pour manger dans Christianshavn, une bonne adresse est
<a href="https://www.openstreetmap.org/node/940424834">Lagkagehuset</a> qui fait de
bonnes pâtisseries, des sandwiches (50 <span class="caps">DKK</span>) et des salades (70 <span class="caps">DKK</span>). Comme
(presque) partout au Danemark, aucun problème pour trouver de la nourriture
végétarienne, végétalienne ou sans gluten !</p>
<p>L’après-midi, direction la Suède, juste en face, de l’autre côté du pont
<a href="https://www.openstreetmap.org/way/370256014#map=11/55.6230/12.8856">Øresundbron</a>.
Notre plan était de passer une nuit à Malmö et de faire un tour en Scanie,
entre <a href="https://www.openstreetmap.org/node/26804505">Malmö</a>,
<a href="https://www.openstreetmap.org/node/15412058">Helsingborg</a>,
<a href="https://www.openstreetmap.org/node/21040320">Helsingør</a> et
<a href="https://www.openstreetmap.org/relation/2468628">Lund</a>.</p>
<p>Le bon plan pour faire ça, c’est d’acheter un billet <a href="https://www.skanetrafiken.se/sa-reser-du-med-oss/valj-ratt-biljett/">“Sound
Around”</a>
(malheureusement, le site des transports locaux en Scanie est uniquement en
suédois, avec une traduction automatique :/). Le billet coûte 299 <span class="caps">SEK</span> (249 <span class="caps">DKK</span>
pour les étudiants) et permet de faire, pendant deux jours :</p>
<ul>
<li>Une traversée du détroit (dans un sens ou dans l’autre) par le train sur le pont.</li>
<li>Une traversée du détroit (dans un sens ou dans l’autre) par le
ferry entre Helsingborg et Helsingør.</li>
<li>Autant de trajets qu’on veut en Scanie, du côté suédois (tous les trains
entre les villes et tous les bus, dans les villes ou entre les villes).</li>
<li>Autant de trajets qu’on veut du côté danois, sur les trains de la <span class="caps">DSB</span> (entre
les villes), le S-tog, le métro et les bus (dont ceux à Copenhague).</li>
</ul>
<p>Du coup, ce billet a couvert tous nos déplacements à partir de ce moment
jusqu’au départ pour Göteborg. Le billet peut être <a href="https://www.skanetrafiken.se/sa-reser-du-med-oss/valj-ratt-biljett/">acheté en
ligne</a>
(et c’est visiblement une carte qui vous est envoyée par la poste) ou dans un
point de vente en Suède. Au Danemark, le seul point de vente est l’<a href="https://www.openstreetmap.org/node/280956680">office de
tourisme</a> en face de la gare.
Dans ce cas, on vous donne un petit billet papier sur laquelle vous devez
inscrire la date de début et à présenter aux contrôleurs à chaque contrôle. Il
n’y a rien à badger à chaque montée.</p>
<p><strong>Note</strong> : Il y a une imprécision sur le site et ce n’est pas clair si le billet
est valable 48h ou deux jours. Si vous l’achetez au Danemark, c’est assez
clair par contre car il n’y a qu’une case pour marquer la date de début de
validité. Le ticket est valable ce jour-ci et le lendemain.</p>
<p>C’est parti direction Malmö en prenant l’Øresundståg, le train grande vitesse
qui relie Copenhague, l’aéroport de Copenhague et la Suède en passant par le
pont. Compter 40 minutes entre Copenhague et Malmö, les trains sont très
réguliers et circulent quasiment 24h/24.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j5/DSC07705.JPG" title="L'Øresundståg">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j5_mini/DSC07705.JPG"
style="max-width: 50%"
alt="L'Øresundståg" />
</a>
</p>
<h3>Malmö</h3>
<p>Les principales choses à voir à Malmö sont :</p>
<ul>
<li>La <a href="https://www.openstreetmap.org/way/28415187#map=18/55.60644/13.00482">Sankt Petri
kyrka</a>
qui est malheureusement fermée pour travaux jusqu’en décembre 2018.</li>
<li><a href="https://www.openstreetmap.org/node/3414505433">Ebbas Hus</a>, une <a href="https://malmo.se/Kultur--fritid/Kultur--noje/Museer--utstallningar/Malmo-Museer/Sprak/In-English/Other-museums-and-buildings/Ebbas-House.html">toute petite
maison</a>
coincée entre de grands bâtiments modernes.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j5/DSC07710.JPG" title="Ebba Hus">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j5_mini/DSC07710.JPG"
style="max-width: 50%"
alt="Hebba Hus" />
</a>
</p>
<ul>
<li>Le <a href="https://www.openstreetmap.org/way/35724417">Moderna Museet</a>, une antenne
du musée d’art moderne de Stockholm. Entrée gratuite, mais on est arrivé
trop tard :(</li>
<li>La <a href="https://www.openstreetmap.org/way/28482245">Sankt Johannes kyrka</a> et son
architecture étrange avec ses tours rondes.</li>
<li>Le <a href="https://www.openstreetmap.org/way/28482240">Konsthall</a>, un grand centre
d’expositions (temporaires) d’art contemporain. Entrée gratuite.</li>
<li>La <a href="https://www.openstreetmap.org/relation/2577882">Lilla Torg</a>, une petite
place avec de vieux bâtiments à colombages.</li>
<li>La <a href="https://www.openstreetmap.org/relation/3614792">Stortorget</a>, la place
principale. On y trouve en particulier <a href="https://www.openstreetmap.org/node/328997830">l’hôtel de
ville</a> et une <a href="https://www.openstreetmap.org/node/444860330">pharmacie
ancienne</a> avec de jolies
boiseries. Ne pas manquer les publicités peintes sur le côté gauche du
bâtiment et le <a href="https://www.openstreetmap.org/way/37905133">petit passage</a>
à droite.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j5/DSC07719.JPG" title="Stortorget">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j5_mini/DSC07719.JPG"
style="max-width: 50%"
alt="Stortorget" />
</a>
</p>
<ul>
<li>Le centre historique, entre les canaux, autour de la Stortorget.</li>
<li>La <a href="https://www.openstreetmap.org/relation/282978">citadelle</a>, qui abrite le
musée de la ville (fermé également quand on y est passé :().</li>
<li>Les petites cabanes autour du <a href="https://www.openstreetmap.org/way/46104286">marché au
poisson</a>.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j5/DSC07726.JPG" title="Le marché aux poissons">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j5_mini/DSC07726.JPG"
style="max-width: 50%"
alt="Le marché aux poissons" />
</a>
</p>
<ul>
<li>Le quartier ultramoderne (et qui veut être écologique) de <a href="https://www.openstreetmap.org/relation/3050114#map=15/55.6090/12.9818">Västra
Hamnen</a>.
Il est au bord du détroit (avec quelques pontons et plages) et permet de
profiter de jolies vues sur le pont Øresundbron. C’est également dans ce
quartier qu’on trouve la <a href="https://www.openstreetmap.org/way/30926877">Turning
Torso</a>, une tour d’habitation
moderne de 54 étages (la plus haute de Scandinavie !) à l’architecture
assez unique.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j5/DSC07747.JPG" title="Turning Torso">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j5_mini/DSC07747.JPG"
style="max-width: 50%"
alt="Turning Torso" />
</a>
</p>
<p>Pour loger à Malmö, on avait trouvé un tarif intéressant à l’<a href="https://hotel-garden-malmo.h-rez.com/index_fr.htm">Hôtel
Garden</a> sur Booking (120 €
pour deux nuits). Il est <a href="https://www.openstreetmap.org/node/444832884">très bien
situé</a>), a 4 étoiles, un sauna
et une terrasse. Les chambres ne sont pas très grandes mais c’est très
raisonnable quand même. Le petit déjeuner est inclus et vraiment super (avec
plein de choix, viennoiseries, muesli, œufs, charcuteries, sashimis, etc,
j’ai rarement vu un petit déjeuner d’hôtel aussi fourni). Il semblerait que
l’hôtel puissent louer / prêter des vélos pour se déplacer facilement, mais on
n’a pas essayé.</p>
<p>Pour manger à Malmö, on a testé
<a href="https://www.openstreetmap.org/node/444856134">Max</a>, une chaîne de fast-foods
suédoise, à la Mc Donald’s. C’est globalement mieux que Mc Donald’s (en
France, on n’a pas testé Mc Donald’s en Suède), compter entre 5 et 10 €.
Comme partout en Suède, il y a de nombreuses options végétariennes (souvent
avec du <a href="https://fr.wikipedia.org/wiki/Halloumi">halloumi</a>, ielles en mettent
partout) ou végétaliennes.</p>
<h2>6e jour, un tour en Scanie</h2>
<p>Pour cette journée, on avait prévu de faire un tour en Scanie (et de profiter
des voyages illimités inclus dans notre billet de transport !). Au programme :
<a href="https://www.openstreetmap.org/node/15412058">Helsingborg</a>,
<a href="https://www.openstreetmap.org/node/21040320">Helsingør</a> et
<a href="https://www.openstreetmap.org/relation/2468628">Lund</a>.</p>
<h3>Helsingborg</h3>
<p>Helsingborg est située sur le détroit de l’Øresund, à un peu moins d’une heure de
train de Malmö. Pour y aller, on peut prendre soit un Øresundståg (les trains
qui relient le Danemark et la Suède puis continuent leur route en Suède), soit
un Pågatåg (les <span class="caps">TER</span> de Scanie).</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j6/DSC07749.JPG" title="Pågatåg">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j6_mini/DSC07749.JPG"
style="max-width: 50%"
alt="Pågatåg" />
</a>
</p>
<p>En sortant de la gare, on arrive très vite sur
l’<a href="https://www.openstreetmap.org/way/169560417">hôtel de ville</a> et
<a href="https://www.openstreetmap.org/way/32460500">Stortorget</a> (la place
principale). Au bout de celle-ci, ne pas rater <a href="https://www.openstreetmap.org/way/378122209#map=19/56.04743/12.69624">les
escaliers</a>
qui montent à
<a href="https://www.openstreetmap.org/way/236992894#map=19/56.04829/12.69749">Kärnan</a>,
un vestige de l’ancienne forteresse. On y a une vue imprenable sur le port et
le détroit. Malheureusement les escaliers et les terrasses de la citadelle
sont fermés jusqu’en 2019.</p>
<p>On a fait un tour dans les <a href="https://www.openstreetmap.org/way/51442037#map=18/56.04531/12.69783">petites rues
piétonnes</a>
autour de la <a href="https://www.openstreetmap.org/way/485729089">Sankta Maria kyrka</a>.</p>
<p>La <a href="https://www.openstreetmap.org/way/89202723">Dunkers kulturhus</a> un peu plus
loin, au bord du port, héberge une exposition gratuite sur l’histoire de la
ville et des expositions temporaires (70 <span class="caps">SEK</span>, gratuit pour les moins de 18
ans). C’est aussi un bon spot pour se poser, recharger et planifier le reste
de la journée !</p>
<h3>Helsingør</h3>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j6/DSC07756.JPG" title="Ferry">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j6_mini/DSC07756.JPG"
style="max-width: 50%"
alt="Ferry" />
</a>
</p>
<p>Pour traverser jusqu’à Helsingør, on peut prendre le
<a href="https://www.scandlines.se/tider-och-priser/biljettyper-och-priser/helsingborg-helsingor">ferry</a>
(une traversée incluse dans le billet “Sound Around”). Il y en a quasiment en
continu et la traversée est très courte (moins de 20 minutes). Comme sur tous
les ferries qu’on a pris au Danemark et en Suède, il y a une cafétéria à bord
qui fait des sandwiches et saucisses à des prix plutôt raisonnables. Ça peut
dépanner :)</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j6/DSC07760.JPG" title="Helsingør">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j6_mini/DSC07760.JPG"
style="max-width: 50%"
alt="Helsingør" />
</a>
</p>
<p>À Helsingør, ne pas rater :
* La <a href="https://www.openstreetmap.org/relation/1610073">Sankt Mariæ Kirke og Vor Frue
Kloster</a>, une jolie église
avec un petit cloître.
* Une autre église, la <a href="https://www.openstreetmap.org/way/113512470">Sankt Olai Kirke</a>.
* Les petites rues piétonnes du vieux centre, avec leurs jolies petites
maisons, notamment
<a href="https://www.openstreetmap.org/way/300736999">Sanct Anna Gade</a> et les rues
entre <a href="https://www.openstreetmap.org/way/169101882">Axeltorv</a> et la gare.
* Les bâtiments modernes autour de
<a href="https://www.openstreetmap.org/way/113512471">Kulturværftet</a>, à la place
des anciens chantiers navals. Il y a aussi un <a href="https://www.openstreetmap.org/way/192140803">musée
maritime</a> dans une ancienne
cale sèche, malheureusement ouvert uniquement le weekend hors saison.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j6/DSC07769.JPG" title="Les anciens chantiers navals">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j6_mini/DSC07769.JPG"
style="max-width: 50%"
alt="Les anciens chantiers navals" />
</a>
</p>
<ul>
<li>Le <a href="https://www.openstreetmap.org/relation/1588209">château de Kronborg</a>
(voir aussi <a href="https://fr.wikipedia.org/wiki/Ch%C3%A2teau_de_Kronborg">sa page
Wikipédia</a>), le
château qui sert de cadre à la pièce <em>Hamlet</em> de Shakespeare, classé au
patrimoine mondial de l’<span class="caps">UNESCO</span>. L’entrée est à 90 <span class="caps">DKK</span> (80 <span class="caps">DKK</span> pour les
étudiants). Ne pas rater l’ascension de la tour (c’est haut !), d’où on a
une vue imprenable sur le détroit. Ne pas rater non plus la visite des
souterrains (lampe torche conseillée, ou téléphone portable à défaut) qui
abritent entre autres une statue de <a href="https://fr.wikipedia.org/wiki/Ogier_de_Danemarche">Holger
Danske</a>, un héros
légendaire danois.</li>
</ul>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j6/DSC07806.JPG" title="Le château de Kronborg">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j6_mini/DSC07806.JPG"
style="max-width: 45%"
alt="Le château de Kronborg" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j6/DSC07802.JPG" title="Holger Danske">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j6_mini/DSC07802.JPG"
style="max-width: 45%"
alt="Holger Danske" />
</a>
</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j6/DSC07789.JPG" title="Helsingør">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j6_mini/DSC07789.JPG"
style="max-width: 50%"
alt="Helsingør" />
</a>
</p>
<p>Quelques liens utiles sur Helsingør :</p>
<ul>
<li><a href="http://www.ecribouille.net/visite-hamlet-forteresse-kronborg/">http://www.ecribouille.net/visite-hamlet-forteresse-kronborg/</a></li>
</ul>
<h3>Lund</h3>
<p>On repart ensuite pour la Scanie, du côté suédois, à Lund plus précisément.
Deux options pour le trajet, à peu près équivalentes en temps :
* Soit reprendre le train à Helsingør directement pour Lund. Compter 1h40. Le
train passe par le Øresundbron, donc c’est une bonne option si vous
n’avez pas encore utilisé ce passage dans votre billet “Sound Around”.
Elle vous permet aussi de refaire un tour en train au Danemark (même si le
paysage sur ce trajet n’est pas exceptionnel).
* Soit reprendre le ferry pour Helsingborg (compter 5 € par personne et 20
minutes) puis le train de Helsingborg à Lund (inclus dans tous les cas
avec le billet “Sound Around”, compter 40 minutes). C’est probablement
l’option la plus rapide, mais ça dépend des combinaisons des horaires.</p>
<p>Lund est une ville universitaire (son université est la seconde plus
ancienne de Suède et une des mieux cotées de Suède aujourd’hui). À voir à
Lund :
* Les bâtiments de l’Université et notamment le <a href="https://www.openstreetmap.org/way/39440936#map=18/55.70577/13.19424">bâtiment
principal</a>
* La <a href="https://www.openstreetmap.org/way/148133843#map=18/55.70447/13.19452">cathédrale de Lund</a>
* Le <a href="https://www.openstreetmap.org/way/13713494#map=17/55.70425/13.20275">Jardin
botanique</a>
* Les jolies petites rues derrière la cathédrale, notamment
<a href="https://www.openstreetmap.org/way/335284122#map=19/55.70498/13.19924">Adelgatan</a>
* Quelques photos sont sur <a href="https://www.monpetitnuage.com/road-trip-suede-lund/">ce blog de
voyage</a>.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j6/DSC07813.JPG" title="Lund">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j6_mini/DSC07813.JPG"
style="max-width: 30%"
alt="Lund" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j6/DSC07807.JPG" title="Cathédrale de Lund">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j6_mini/DSC07807.JPG"
style="max-width: 30%"
alt="Cathédrale de Lund" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j6/DSC07814.JPG" title="Université de Lund">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j6_mini/DSC07814.JPG"
style="max-width: 30%"
alt="Université de Lund" />
</a>
</p>
<p>Il y a aussi quelques musées, mais ils ferment tôt et il était malheureusement
trop tard…</p>
<p>Pour manger, on n’a pas cherché très loin et on est allé chez <a href="https://www.openstreetmap.org/node/1279061789">Kebab
Huset</a> (il fallait bien tester
un kebab en Suède pour voir si c’était pareil qu’en France :). Ratio
quantité / prix excellent et, Suède oblige, on peut avoir de la viande ou des
falafels dans son kebab :)</p>
<p>Le soir, retour à Malmö pour y passer la nuit, 15 minutes de train et il y a
des trains quasiment 24h/24.</p>
<h2>7e jour, Göteborg</h2>
<p>Le lendemain, départ pour
<a href="https://www.openstreetmap.org/node/25930131">Göteborg</a> en train grande
vitesse <span class="caps">SJ</span>. Départ à 8h34 de Malmö, arrivée à 11h00 à Göteborg, pour 195 <span class="caps">SEK</span>
par personne (réduction pour les étudiants avec une carte <span class="caps">ISIC</span>, 166 <span class="caps">SEK</span>). On
découvre les trains suédois <a href="https://en.wikipedia.org/wiki/Regina_(train)"><span class="caps">SJ3000</span> /
X55</a> qui sont grands conforts,
la seconde classe ressemblerait presque à notre première classe ! Sur les
trains suédois de <a href="http://sj.se/"><span class="caps">SJ</span></a>, on peut choisir son siège comme dans
les avions, à l’achat du billet. Il peut être intéressant de prendre un siège
sur la gauche du train pour ce trajet, on aperçoit régulièrement la mer et le
paysage est très joli !</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j7/DSC07815.JPG" title="Train Malmö - Göteborg">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j7_mini/DSC07815.JPG"
style="max-width: 50%"
alt="Train Malmö - Göteborg" />
</a>
</p>
<p><strong>Note</strong> : À Göteborg (comme dans toutes les gares suédoises en fait, j’ai
l’impression), il y a <a href="https://www.speed-services.se/en/lockers/speed-locker/116/goteborg-central-station/">des consignes à
bagages</a>.</p>
<p>À Göteborg, il y a de classiques <a href="https://www.goteborg.com/en/citycard/">cartes
pour touristes</a> mais elles n’incluent
pas les transports, ce qui est nettement moins rentable du coup. Pour les
transports, le billet de base est à 30 <span class="caps">SEK</span> (27 <span class="caps">SEK</span> si acheté dans
<a href="https://www.vasttrafik.se/en/tickets/more-about-tickets/vasttrafik-to-go/">l’application</a>).
Il y a aussi des billets 24h (95 <span class="caps">SEK</span>) ou 72h (190 <span class="caps">SEK</span>) (voir <a href="https://www.vasttrafik.se/en/tickets/day-tickets/Goteborg/">cette
page</a>). Si acheté
dans l’application, les billets sont valables 24h/72h à partir de l’activation
(sur papier, c’est probablement pareil, mais on n’a pas testé). Les billets
journée peuvent être particulièrement intéressants si vous allez dans l’archipel.</p>
<p><strong>Note</strong> : Il y a plusieurs zones de transport à Göteborg et il n’est pas
toujours facile de trouver le bon ticket. La plupart de vos voyages (y compris
dans l’archipel sud) seront couverts par la zone “Göteborg”. En cas de doute,
l’application est assez bien faite et assez claire sur les billets utilisables.</p>
<p>Pour ce premier jour à Göteborg, il faisait gris (et franchement mauvais en
fait…), du coup on s’est concentré sur le centre-ville où on pouvait
rapidement se réfugier dans un magasin et les musées. :)</p>
<p>Pour manger le midi, un très bon plan est le
<a href="https://www.openstreetmap.org/way/28901326#map=17/57.70351/11.96834">Saluhallen</a>,
un grand (et beau, en fer à la Eiffel) marché couvert en centre-ville. On y
trouve les étals habituels d’un marché couvert ainsi que de nombreux stands
qui servent des plats à des tarifs très raisonnables. On a testé la spécialité
locale, le filet de hareng grillé avec de la purée de pommes de terre, très
bons, copieux et pas chers ! Pas très loin, on trouve aussi plusieurs cafés
<a href="https://damatteo.se/">da Matteo</a> qui servent du très bon café, par exemple
<a href="https://www.openstreetmap.org/node/1931250746#map=18/57.70335/11.96321">celui-ci</a>
sur
<a href="https://www.openstreetmap.org/way/4265195#map=18/57.70356/11.96419&layers=N">Vallgatan</a>,
une des rues très commerçantes du centre-ville (où on trouve aussi quelques
magasins suédois de design comme
<a href="https://www.openstreetmap.org/node/2146680095">DesignTorget</a> ou de vêtements).</p>
<p>Après ce tour en centre-ville, ne pas rater <a href="https://www.openstreetmap.org/way/123354983#map=17/57.70462/11.97386&layers=N">le jardin
botanique</a>
et en particulier la <a href="https://www.openstreetmap.org/way/45408372">palmeraie</a>,
impressionnante serre remplie de palmiers et cactées, en libre accès.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j7/DSC07822.JPG" title="La serre du jardin botanique">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j7_mini/DSC07822.JPG"
style="max-width: 50%"
alt="La serre du jardin botanique" />
</a>
</p>
<p>Malheureusement, le <a href="https://www.openstreetmap.org/node/1852952439#map=18/57.70012/11.97427">Röhsska Museum of Design <span class="amp">&</span> Applied
Art</a>
était fermé pour travaux. Le <a href="https://www.openstreetmap.org/way/158286965">Göteborgs
konstmuseum</a> était ouvert et vaut
vraiment une visite (entrée gratuite jusqu’à 25 ans, 60 <span class="caps">SEK</span> sinon, payable
uniquement en <span class="caps">CB</span>) !</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j7/DSC07823.JPG" title="Konstmuseum">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j7_mini/DSC07823.JPG"
style="max-width: 50%"
alt="Konstmuseum" />
</a>
</p>
<p>Un peu plus loin derrière, de l’autre côté des bâtiments de l’université, on
trouve le
<a href="https://www.openstreetmap.org/way/132081062#map=17/57.69421/11.98991">Världskulturmuseet</a>,
un musée (entrée gratuite) sur les cultures du monde, dans un bâtiment ultra
moderne, avec des expositions temporaires sur des thèmes de société (sur la
guerre en Syrie et les réfugiés quand on y est passé). On y est arrivé trop
tard, mais le musée fait des nocturnes le lendemain (mercredi soir), pratique !</p>
<p>Dans le même quartier, on trouve aussi
<a href="https://www.openstreetmap.org/relation/5179991#map=16/57.6946/11.9928">Liseberg</a>,
un grand parc d’attractions, malheureusement fermé à cette période de l’année
(il rouvre pour Halloween et Noël seulement).</p>
<p>On est donc redescendu faire un tour dans
<a href="https://www.openstreetmap.org/relation/1517292">Haga</a>, un ancien quartier
ouvrier avec des maisons pittoresques né lorsque la ville s’est étendue hors
de ses remparts défensifs. Le quartier est aujourd’hui totalement gentrifié et
très bobo/hipster. Pour faire une pause dans ce quartier, ne pas rater le
<a href="https://www.openstreetmap.org/node/4344957464">Café Husaren</a> qui fait
beaucoup de gâteaux et de pâtisseries (dont les Hagabulle, d’énormes
et très bons kannelbullars, 60 <span class="caps">SEK</span>), ainsi que des lasagnes, des salades, des
sandwiches et des quiches (entre 8 et 10 €). Pas mal d’options végétariennes et
vegans clairement indiquées aussi ! Dans le quartier, ne pas manquer non plus
la <a href="https://www.openstreetmap.org/way/116438616">Hagakyrkan</a>, aux horaires
d’ouverture malheureusement assez aléatoires apparement :/</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j7/DSC07930.JPG" title="Hagabulle">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j7_mini/DSC07930.JPG"
style="max-width: 50%"
alt="Hagabulle" />
</a>
</p>
<p>Finalement, on a fini la journée en montant en haut de la colline de <a href="https://www.openstreetmap.org/way/32871212">Skansen
Kronan</a>, une ancienne tour de
défense de la ville de Göteborg. On y a une vue à 360° sur la ville et la mer.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j7/DSC07826.JPG" title="Vue depuis Skansen Kronan">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j7_mini/DSC07826.JPG"
style="max-width: 90%"
alt="Vue depuis Skansen Kronan" />
</a>
</p>
<p>À Göteborg, on logeait dans un Airbnb dans le quartier de
<a href="https://www.openstreetmap.org/relation/1517296">Majorna</a>, à côté de
<a href="https://www.openstreetmap.org/node/2087931321">Mariaplan</a>. C’est un peu
excentré mais très bien connecté avec le tramway jusqu’au centre-ville et à la
gare, nettement moins cher que ce qu’on trouve en ville et le quartier est
très sympa ! C’est aussi sur la ligne de tramway qui va à Saltholmen pour les
départs en ferries vers l’archipel.</p>
<h2>8e jour, l’archipel de Göteborg</h2>
<p>Le lendemain, on découvre (enfin :) le climat suédois avec 3° C au réveil et
-1° C ressenti, mais un super soleil. Super, direction l’embarcadère de
<a href="https://www.openstreetmap.org/node/313760549">Saltholmen</a>, au bout du
tramway 11, pour une journée dans le sud de l’archipel. De nombreuses îles
sont accessibles en moins d’une heure de ferry, qui fonctionne comme les bus
et tramways (liaisons régulières, même billet valable).</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j8/DSC07836.JPG" title="Les ferries pour l'archipel">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j8_mini/DSC07836.JPG"
style="max-width: 50%"
alt="Les ferries pour l'archipel" />
</a>
</p>
<p>Ce n’est pas forcément évident de s’y retrouver dans les îles et les horaires,
surtout qu’à cette saison les ferries ne sont pas forcément aussi réguliers.
Dans le doute, le site de
<a href="https://www.vasttrafik.se/en/travel-planning/timetables/">VästTrafik</a> (ou
l’application) sont bien faits et permettent d’être sûr des horaires (et il y
a du réseau quasiment partout dans l’archipel). Les ferries sont néanmoins
très réguliers et circulent toute la journée (et en soirée).</p>
<p>Les horaires actuels (brochure disponible à l’embarcardère aussi), sont
disponibles
<a href="https://info.vasttrafik.se/TimeTables/S%C3%B6dra%20sk%C3%A4rg%C3%A5rden%20Uppdaterad%20180827-181208.pdf">ici</a>,
avec la carte des liaisons au début. Attention aux indices <em>a</em> et <em>t</em>. <em>a</em>
désigne un arrêt qu’il faut demander explicitement au conducteur du bateau
(sinon, il ne s’y arrête pas, on ne peut donc le prendre qu’à la descente).
<em>t</em> veut dire qu’il faut appeler le numéro indiqué 30 minutes en avance pour
que le bateau s’arrête.</p>
<p>Il n’y a pas grand chose pour trouver à manger à Saltholmen. Il y a quelques
cafés et restaurants sur les îles (mais souvent fermés hors saison) et
quelques supermarchés (qui peuvent dépanner, prix supérieur au continent).
L’idéal est probablement de prévoir un pique-nique, s’il fait beau :)</p>
<p>On est parti vers 9h pour aller à
<a href="https://www.openstreetmap.org/way/4131505">Vrångö</a> vers 10h. Vrångö est l’île
la plus éloignée du continent. Là-bas, on a fait un <a href="https://www.openstreetmap.org/way/8656750#map=16/57.5668/11.7861">tour au
sud</a>, à
travers la réserve naturelle. De là, on peut voir les autres îles de la
réserve naturelle. Il y a de nombreuses tables de pique-nique le long du
chemin, idéal pour pique-niquer au bord de l’eau ! De l’autre côté, ne pas
manquer <a href="https://www.openstreetmap.org/node/2935184713">la petite cabane</a>
perchée en haut d’un rocher, qui permet d’avoir une vue d’ensemble de toute
l’île. Il y a quelques jolies maisons pittoresques dans le village. Il y a
aussi <a href="https://www.openstreetmap.org/way/297520589">un café</a> qui était encore
ouvert à cette saison au niveau de l’embarcadère et une
<a href="https://www.openstreetmap.org/way/297355016">épicerie</a>. Pour faire un tour
tranquillement et pique-niquer, compter au moins 2h sur l’île.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j8/DSC07843.JPG" title="Vrångö">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j8_mini/DSC07843.JPG"
style="max-width: 45%"
alt="Vrångö" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j8/DSC07854.JPG" title="Vrångö">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j8_mini/DSC07854.JPG"
style="max-width: 45%"
alt="Vrångö" />
</a>
</p>
<p>On est ensuite parti en direction de
<a href="https://www.openstreetmap.org/way/4131343#map=14/57.6016/11.8039&layers=N">Donsö</a>.
Il y a un <a href="https://www.openstreetmap.org/node/605530611#map=17/57.59872/11.79512&layers=N">joli petit
port</a>
avec des petits cabanons de pêcheurs. On peut ensuite rejoindre l’île voisine,
<a href="https://www.openstreetmap.org/relation/6429433#map=14/57.6094/11.7741&layers=N">Styrsö</a>
à pied par <a href="https://www.openstreetmap.org/way/52305497">le pont</a> qui les relie.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j8/DSC07883.JPG" title="Donsö">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j8_mini/DSC07883.JPG"
style="max-width: 50%"
alt="Donsö" />
</a>
</p>
<p>Sur Styrsö, il y a <a href="https://www.openstreetmap.org/relation/5477124#map=15/57.6076/11.7835&layers=N">un
chemin</a>
qui fait tout le tour de l’île par le Sud et offre de très jolis paysages. À
un moment, vous pouvez dévier pour monter au sommet du <a href="https://www.openstreetmap.org/node/3008420726">point le plus
haut</a> de l’île. Des dépliants
(en suédois) sont disponibles à l’embarcadère de <a href="https://www.openstreetmap.org/node/264139668">Styrsö
Skäret</a> pour vous accompagner
pendant la balade. Des dépliants en anglais sont apparemment disponibles à la
pension, qu’on n’a pas trouvée… Visiblement <a href="https://www.openstreetmap.org/node/3008420726">c’est
ici</a>. On a fini la promenade à
l’embarcadère de <a href="https://www.openstreetmap.org/node/313760631">Styrsö Tången</a>
pour reprendre le bateau, vers 16h.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j8/DSC07900.JPG" title="Styrsö">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j8_mini/DSC07900.JPG"
style="max-width: 45%"
alt="Styrsö" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j8/DSC07906.JPG" title="Styrsö">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j8_mini/DSC07906.JPG"
style="max-width: 45%"
alt="Styrsö" />
</a>
</p>
<p>On aurait voulu faire un dernier arrêt sur
<a href="https://www.openstreetmap.org/way/4131037">Asperö</a> avant de rentrer, mais les
horaires ne se sont pas bien goupillés et il aurait fallu attendre une heure…
Sachez que pour rejoindre Asperö, l’arrêt <a href="https://www.openstreetmap.org/node/265377538">Asperö
Östra</a>, à l’est, n’est pas très
bien desservi, en particulier en fin de journée, car il est du côté opposé au
village. <a href="https://www.openstreetmap.org/node/829771154">Asperö Norra</a> par
contre est dans le village et desservi tout le temps de façon très régulière,
par la ligne entre le continent et
<a href="https://www.openstreetmap.org/node/829768652">Brännö</a>.</p>
<p>Sur les îles de l’archipel, il n’y a pas de voitures. La plupart des habitants
se déplacent donc avec ces étranges mobylettes.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j8/DSC07872.JPG" title="Mobylettes">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j8_mini/DSC07872.JPG"
style="max-width: 50%"
alt="Mobylettes" />
</a>
</p>
<p>Quelques liens utiles sur l’archipel de Göteborg :</p>
<ul>
<li><a href="https://www.inthemoodforfood.fr/suede-goteborg-archipel-guide/">https://www.inthemoodforfood.fr/suede-goteborg-archipel-guide/</a></li>
<li><a href="https://en.m.wikivoyage.org/wiki/Gothenburg_Archipelago">https://en.m.wikivoyage.org/wiki/Gothenburg_Archipelago</a></li>
</ul>
<p>Le soir, on profite que ce soit mercredi et que la plupart des musées fassent
des nocturnes. En particulier, on en profite pour aller voir le <a href="https://www.openstreetmap.org/way/41269418">Röda Sten
Konsthall</a> au bout de la <a href="https://www.openstreetmap.org/way/501233818#map=17/57.69027/11.90454&layers=N">Klippans
Strandpromenad</a>.
Klippans est un quartier d’anciennes usines et manufactures (et donc de très
beaux bâtiments anciens en brique !). On a vu sur les grues du port en face
aussi, de l’autre côté du <a href="https://www.openstreetmap.org/way/4303422#map=16/57.6912/11.9016&layers=N">pont de style
newyorkais</a>
:) Ne pas se laisser impressionner par l’aspect industriel et brut des lieux
et la situation un peu isolée du musée, il est vraiment super (et le quartier
aussi) ! Le Röda Sten a récupéré cette ancienne fabrique et l’a laissée “en
l’état” (y compris les tags aux murs). Il y a des expositions temporaires, sur
notre rapport au politique et la démocratie quand on y est passé, avec des
installations et des photographies. Il y a souvent des <em>performances</em> ou des
soirées organisées (il y avait un débat, en suédois malheureusement, ce soir-là).</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j8/DSC07913.JPG" title="Le pont newyorkais">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j8_mini/DSC07913.JPG"
style="max-width: 50%"
alt="Le pont newyorkais" />
</a>
</p>
<p>Si vous êtes motivés, en suivant la Klippans Standpromenad dans l’autre sens,
on peut rejoindre le centre-ville de Göteborg en suivant le bord de l’eau.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j8/DSC07912.JPG" title="Klippans">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j8_mini/DSC07912.JPG"
style="max-width: 50%"
alt="Klippans" />
</a>
</p>
<p>On a aussi profité des nocturnes du mercredi pour aller voir le
<a href="https://www.openstreetmap.org/way/132081062">Världskulturmuseet </a> qu’on
n’avait pas pu voir la veille.</p>
<h2>9e jour, un dernier tour à Göteborg et Stockholm</h2>
<p>Le matin, on en profite pour refaire un petit tour dans la vieille ville de
Göteborg, historiquement à l’intérieur des remparts. Ne pas rater le
<a href="https://www.openstreetmap.org/node/508572909">Maritimams</a>, un musée maritime
(malheureusement fermé à cette période de l’année, mais on peut quand même
voir les bateaux depuis le quai) avec de nombreux bateaux dont un sous-marin
et des navires militaires. On aperçoit aussi le <a href="https://www.openstreetmap.org/way/175648796">gratte-ciel rouge à
lèvres</a> au bout du quai. Ne pas
manquer non plus le <a href="https://www.openstreetmap.org/way/44697495">Kronhuset</a>,
un des plus vieux bâtiments de la ville, initialement construit au milieu du
<span class="caps">XVIII</span><sup>e</sup> siècle pour stocker des affaires militaires, plus tard
converti en maison du parlement et aujourd’hui une salle de concert. Enfin, il
y a la très jolie <a href="https://www.openstreetmap.org/way/41530300">Feskekörka</a> qui
est désormais un marché aux poissons.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j9/DSC07914.JPG" title="Kronhuset">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j9_mini/DSC07914.JPG"
style="max-width: 30%"
alt="Kronhuset" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j9/DSC07923.JPG" title="Les grues du port">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j9_mini/DSC07923.JPG"
style="max-width: 30%"
alt="Les grues du port" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j9/DSC07929.JPG" title="Feskekörka">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j9_mini/DSC07929.JPG"
style="max-width: 30%"
alt="Feskekörka" />
</a>
</p>
<p>Départ en train de Göteborg à 12h34, arrivée à 15h35 à Stockholm, compter 195
<span class="caps">SEK</span> par personne (166 <span class="caps">SEK</span> pour les étudiants). Entre Göteborg et Stockholm, il
y a quelques jolis paysages et de nombreux lacs sur le côté gauche ! On avait
un <a href="https://fr.wikipedia.org/wiki/SJ2000">X2000</a> cette fois, un cran
en-dessous du <span class="caps">SJ3000</span>, notamment parce qu’il est plus vieux. C’est quand même
très confortable et au moins équivalent à nos <span class="caps">TGV</span> :)</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j9/DSC07933.JPG" title="Le train Göteborg - Stockholm">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j9_mini/DSC07933.JPG"
style="max-width: 50%"
alt="Le train Göteborg - Stockholm" />
</a>
</p>
<p>En arrivant à la gare de Stockholm, la première mission est de trouver des
billets de transport. On a opté pour des billets 3 jours pour être tranquille
(125 <span class="caps">SEK</span> par personne). On peut les trouver dans les Pressbyrån (petits
bureaux de presse) ou les 7-Eleven notamment, mais il faut alors acheter une
carte rechargeable en plus (20 <span class="caps">SEK</span> par personne, la carte est valable
longtemps et peut être rechargée à la prochaine visite). Sinon, il y a une
boutique <span class="caps">SL</span> dans la gare qui vend des billets normaux, sur papier.</p>
<p>Attention aussi qu’à Stockholm, le <strong>T</strong> veut dire <em>Tunnelbana</em>, métro, et pas
tram. Pour trouver le tram, il faut donc suivre les icônes de tram :)</p>
<p>Après avoir posé nos affaires, on repart faire un tour dans <a href="https://www.openstreetmap.org/relation/5695398">Gamla
Stan</a>, la vieille ville
médiévale, et <a href="https://www.openstreetmap.org/relation/5695401">Riddarholmen</a>,
l’ilôt des chevaliers. C’est trop tard pour visiter les monuments et les
musées, mais on a un premier aperçu de Stockholm (et la vue depuis l’<a href="https://www.openstreetmap.org/way/26224594">Evert
Taubes Terrass</a> doit être super au
coucher de soleil, mais il faisait gris :/).</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j9/DSC08009.JPG" title="Gamla Stan">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j9_mini/DSC08009.JPG"
style="max-width: 45%"
alt="Gamla Stan" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j9/DSC08072.JPG" title="Gamla Stan">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j9_mini/DSC08072.JPG"
style="max-width: 45%"
alt="Gamla Stan" />
</a>
</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j9/DSC08076.JPG" title="Parlement suédois">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j9_mini/DSC08076.JPG"
style="max-width: 50%"
alt="Parlement suédois" />
</a>
</p>
<p>De cette place, on peut prendre un petit bateau (qui fonctionne comme un bus
normal) pour rejoindre l’île de
<a href="https://www.openstreetmap.org/relation/5695402#map=14/59.3151/18.0710&layers=N">Södermalm</a>
(le quartier jeune et branché) juste <a href="https://www.openstreetmap.org/node/5262521845#map=19/59.32132/18.05844&layers=N">en
face</a>.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j9/DSC07950.JPG" title="Södermalm">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j9_mini/DSC07950.JPG"
style="max-width: 50%"
alt="Södermalm" />
</a>
</p>
<p>En grimpant les escaliers derrière l’embarcadère, on peut rejoindre <a href="https://www.openstreetmap.org/way/144024295#map=17/59.32047/18.06296&layers=N">un petit
chemin</a>
en hauteur avec des points de vue sur Gamla Stan et Stockholm en général. On
peut rejoindre ensuite les <a href="https://www.openstreetmap.org/way/454285529">terrasses
Slussen</a> (des écluses),
malheureusement actuellement un grand chantier à ciel ouvert.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j9/DSC08007.JPG" title="Vue depuis Södermalm">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j9_mini/DSC08007.JPG"
style="max-width: 90%"
alt="Vue depuis Södermalm" />
</a>
</p>
<p>Le Södermalm hipster se trouve plutôt autour de
<a href="https://www.openstreetmap.org/relation/3862784">Medborgarplatsen</a> et au sud
de <a href="https://www.openstreetmap.org/way/136886858">Folkungagatan</a> (nommé SoFo,
par inspiration newyorkaise, South of Folkungagatan), tandis que l’ouest le
long de <a href="https://www.openstreetmap.org/way/388628836">Bastugatan</a> est beaucoup
plus résidentiel ou d’anciennes manufactures transformées.</p>
<p>Si vous êtes fans des livres Millenium, une grande partie de l’intrigue se
passe dans Södermalm. Vous trouverez une carte détaillée avec la plupart des
lieux <a href="http://www.losapos.com/millennium%20locations%20in%20stockholm">ici</a>.</p>
<p>Pour manger, on est allé chez <a href="https://www.openstreetmap.org/node/1211022333">Blå
Dörren</a> (la porte bleue, mais
vous n’en verrez pas car le pub n’a pas eu l’autorisation de la ville pour
restaurer la couleur initiale de la porte :). On a pris du hareng frit mariné
dans la moutarde avec des airelles et de la purée et des boulettes d’élan avec
des airelles et de la purée. Les plats étaient excellents et très copieux,
pour un prix raisonnable (15 €), c’est une bonne adresse ! Pas mal de choix
de bières aussi, du cidre et des options végétariennes. L’ambiance est plutôt
pub par contre, donc c’est un peu bruyant.</p>
<p>On a fini la journée en allant voir
<a href="https://www.openstreetmap.org/node/868261113">Fotografiska</a>, le musée de
photographie de Stockholm (entrée à 145 <span class="caps">SEK</span> pour les adultes, 115 <span class="caps">SEK</span> pour les
étudiants). Le musée est ouvert très tard, c’est assez exceptionnel ! Super
expositions, le musée vaut le coup si vous aimez la photographie. Comme
souvent dans les musées de photographie, c’est un peu aride en explications
par contre. Le musée est très mal desservi par les transports en commun par
contre et il faut marcher une quinzaine de minutes au bord des quais (une fois
le chantier passé, la balade n’est pas moche ceci dit :). À noter aussi
quelques images violentes / choquantes qui ne sont pas forcément bien
signalées en amont. :/</p>
<p>Pour loger à Stockholm, c’est assez dur de trouver quelque chose à un tarif
abordable / proche du centre. On a finalement trouvé <a href="https://www.openstreetmap.org/node/2212900018#map=17/59.32410/18.07248&layers=N">Old Town
Lodge</a>,
une auberge de jeunesse pas trop chère (40 € / nuit pour deux en “dortoir”) et <strong>hyper</strong>
bien située, en plein Gamla Stan. Quand on a voulu réserver, toutes les
chambres étaient prises et il ne restait que les “espaces dans le dortoir”.
C’est assez surprenant comme installation : l’<span class="caps">AJ</span> a une grande cave au
sous-sol (très belle voûte en pierre au passage !) et ielles ont simplement
installé des parois en verre pour délimiter des chambres. C’est un dortoir
(les “chambres” ne sont pas fermées en haut), mais vous avez un minimum
d’intimité avec les vitres et les rideaux et vous pouvez laisser vos affaires
sans soucis, les portes fermant à clé. C’est un tarif assez imbattable pour
Stockholm, et c’est finalement vraiment pas mal ! L’auberge de jeunesse était
très propre (chambres, sanitaires, cuisines etc). La qualité de votre sommeil
dépendra par contre beaucoup des voisins et de leur respect du voisinage. On a
eu droit notamment (outre les ronflements qu’on ne maîtrise pas forcément)
à un sèche-cheveux à 23h et un réveil qui sonne pendant 10 minutes à fond à 6h30…</p>
<p><strong>Note</strong> : Si vous voulez réserver chez Old Town Lodge, passez par <a href="http://oldtownlodge.se/en/">leur site
web</a> plutôt que par un site comme Booking. Le
petit-déjeuner (basique) et les serviettes de toilettes et les draps seront
inclus (alors qu’il faudra amener les vôtres ou payer un supplément en passant
par Booking, alors que la chambre est au même prix). Duvets interdits, il faut
amener des draps si vous ne les prenez pas avec la chambre.</p>
<h2>10e jour, Drottningholm</h2>
<p>Le lendemain, on part le matin pour <a href="https://www.openstreetmap.org/relation/29368">l’Hôtel de
Ville</a>, qu’on peut visiter en
visite guidée uniquement, en anglais ou en suédois (110 <span class="caps">SEK</span>, 90 <span class="caps">SEK</span> pour les
étudiants). La visite dure environ 45 minutes (dépliant de visite disponible
<a href="http://www.stockholm.se/PageFiles/298723/franska.pdf">ici</a>) et permet de voir
le hall bleu (qui n’est pas bleu du tout, décidément) où a lieu la cérémonie
de remise des prix Nobel, diverses salles dont la salle du conseil municipal
(où on apprend que les suédois respectent fort bien la parité) et le salon
doré (entièrement recouvert de granito en petits morceaux de verre et d’or) où
a lieu le bal qui suit la remise du prix Nobel. À cette époque de l’année
l’accès à la tour n’est plus possible par contre.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j10/DSC08081.JPG" title="Hôtel de Ville de Stockholm">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j10_mini/DSC08081.JPG"
style="max-width: 45%"
alt="Hôtel de Ville de Stockholm" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j10/DSC08020.JPG" title="Hôtel de Ville de Stockholm">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j10_mini/DSC08020.JPG"
style="max-width: 45%; max-height: 300px;"
alt="Hôtel de Ville de Stockholm" />
</a>
</p>
<p><strong>Note</strong> : Bien vérifier <a href="http://www.stockholm.se/OmStockholm/Stadshuset/">en
ligne</a> avant votre visite les
horaires d’ouverture et des visites guidées. S’il y a des cérémonies
officielles notamment, les visites peuvent être suspendues.</p>
<p>Le midi, on a cherché à manger rapidement avant de partir pour
<a href="https://fr.wikipedia.org/wiki/Ch%C3%A2teau_de_Drottningholm">Drottningholm</a>,
un château appartenant à la famille royale et inscrit au patrimoine mondial de
l’<span class="caps">UNESCO</span>. Du coup, on est retourné chez Max pour tester cette fois la version
“burger haloumi” (végétarien), une découverte surprenante mais vraiment pas
mauvaise ! :)</p>
<p>Pour rejoindre
<a href="https://www.openstreetmap.org/relation/3182815">Drottningholm</a>, le plus
simple est de prendre le métro 17 ou 19 jusqu’à
<a href="https://www.openstreetmap.org/node/4225502315">Brommaplan</a> puis le bus
176/177/etc (c’est indiqué en sortant de la station de métro). Compter 30 à 45
minutes depuis le centre de Stockholm. Le trajet est inclus avec un billet
3 jours. Une autre option est de prendre le
<a href="https://www.stromma.se/fr/stockholm/excursions/excursions-a-la-journee/drottningholm-en-bateau/">ferry</a>
au départ de Stockholm (c’est par contre nettement plus cher et pas inclus
dans le billet :).</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j10/DSC08033.JPG" title="Drottningholm">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j10_mini/DSC08033.JPG"
style="max-width: 45%"
alt="Drottningholm" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j10/DSC08053.JPG" title="Drottningholm">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j10_mini/DSC08053.JPG"
style="max-width: 45%"
alt="Drottningholm" />
</a>
</p>
<p>L’entrée du château est à 130 <span class="caps">SEK</span> (65 <span class="caps">SEK</span> pour les étudiants). Il est possible
de visiter <a href="https://fr.wikipedia.org/wiki/Th%C3%A9%C3%A2tre_du_ch%C3%A2teau_de_Drottningholm">le théâtre du
château</a>
(en supplément, visite guidée uniquement). Il y a aussi des visites guidées du
château (30 <span class="caps">SEK</span> par personne). La visite guidée du château et la visite du
théatre ne sont pas compatibles. On a opté pour la visite du château, mais il
y a pas mal de textes explicatifs dans les salles et si c’était à refaire, le
théâtre vaut probablement plus le coup. Il y a aussi un autre petit château au
fond du parc, le pavillon chinois, qui est fermé à cette période de l’année
(on peut aller le voir à pied, mais pas le visiter).</p>
<p>Pour manger le soir, on est allé à
l’<a href="https://www.openstreetmap.org/node/418226105">Hermitage</a>. C’est un
restaurant végétarien qui sert un buffet uniquement. Il faut compter 15 € le
soir et le weekend, 14 € le midi et 11 € à emporter (vous avez alors trois
barquettes à remplir, probablement l’option la plus intéressante). Le buffet
est plutôt d’inspiration orientale / indienne et bon, mais il n’y a que des
entrées et des plats (et des tartes en supplément, 4 €). Une bonne adresse pour
les végétariens :)</p>
<h2>11e jour, l’archipel de Stockholm (Vahxolm)</h2>
<p>La ville de Stockholm est en réalité sur plusieurs îles et, tout comme à
Göteborg, il y a tout un archipel à proximité, accessible en bateau. Il y a
deux entreprises qui assurent les liaisons avec l’archipel :
<a href="https://waxholmsbolaget.se/">Waxholmsbolaget</a> (publique) et
<a href="https://www.stromma.se/fr/stockholm/">Stromma</a>. Stromma propose plutôt des
croisières, plus chères et avec un tour en bateau mais pas vraiment de temps à
terre. Waxholmsbolaget assure le transport public maritime avec les îles,
comme les bateaux de Göteborg (sauf qu’à Stockholm, les ferries ont une
tarification dédiée). Le site de Waxholmsbolaget est uniquement en suédois,
mais se comprend assez bien. Tous les horaires sont a priori connus de
CityMapper / Google Maps aussi, au besoin.</p>
<p>Il y a de nombreuses îles accessibles directement depuis Stockholm,
facilement. Malheureusement, hors saison, les liaisons sont moins fréquentes
et il est assez difficile de faire plus d’une île dans la journée. Deux îles
sont accessibles facilement à cette période de l’année :
<a href="https://www.openstreetmap.org/relation/4121363">Vaxholm</a> et
<a href="https://www.openstreetmap.org/relation/2663146#map=15/59.4123/18.5641&layers=N">Grinda</a>.
Grinda n’est accessible qu’en bateau et il n’y a rien sur l’île contrairement
à Vaxholm qui est également reliée à Stockholm par un pont et qui a un
village. On a donc opté pour Vaxholm, plus flexible.</p>
<p><strong>Note</strong> : On peut aussi aller à Vaxholm par la route avec le métro 14 puis le
bus 670 (ce qu’on a fait au retour). Le temps de trajet est assez similaire
mais on ne profite pas de la vue sur les îles de l’archipel depuis le bateau.
En revanche, le trajet est inclus avec une carte des transports à Stockholm.</p>
<p>Le départ des ferries Waxholmsbolaget se fait <a href="https://www.openstreetmap.org/node/485995815#map=19/59.32931/18.07497&layers=N">devant le Grand
Hotel</a>.
Les billets s’achètent directement à bord (<span class="caps">CB</span> acceptée) et coûtent 79 <span class="caps">SEK</span> par
personne pour aller à Vaxholm. Compter une demi-journée à Vaxholm.</p>
<p>À Vaxholm, il y a :
* Une <a href="https://www.openstreetmap.org/way/22950413">forteresse</a>, sur une petite
île voisine. Un bateau assure des liaisons régulières lorsque la
forteresse est ouverte. Malheureusement, elle est fermée à cette période
de l’année.
* Plein de jolies maisons rouges en bois dans le village et autour du <a href="https://www.openstreetmap.org/node/364733434">petit
port</a> de l’autre côté de
l’île.
* On a ensuite marché jusqu’à l’autre côté de l’île, plus sauvage,
<a href="https://www.openstreetmap.org/way/23947538">Eriksö</a>. Il y a <a href="https://www.openstreetmap.org/way/39813472#map=15/59.4080/18.3109&layers=N">un
chemin</a>
qui fait le tour de la pointe de l’île et offre de nombreux points de vue
sur les îles voisines.
* La <a href="https://www.openstreetmap.org/way/32435942">place de la mairie</a> avec son
jeu d’échecs en libre service :p</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j11/DSC08061.JPG" title="Vaxholm">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j11_mini/DSC08061.JPG"
style="max-width: 45%"
alt="Vaxholm" />
</a>
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j11/DSC08064.JPG" title="Vaxholm">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j11_mini/DSC08064.JPG"
style="max-width: 45%"
alt="Vaxholm" />
</a>
</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j11/DSC08070.JPG" title="Vaxholm">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j11_mini/DSC08070.JPG"
style="max-width: 50%"
alt="Vaxholm" />
</a>
</p>
<p>Il y a quelques trucs pour manger à Vaxholm, sur le port, dont [une
boulangerie](https://www.openstreetmap.org/node/5325680614 (qui fait des
sandwiches, quiches et lasagnes). Il y a aussi un supermarché pour acheter de
quoi faire un pique-nique.</p>
<p>Quelques liens utiles sur l’archipel :</p>
<ul>
<li><a href="https://visitsweden.fr/larchipel-de-stockholm-un-petit-coin-de-paradis-visiter/">https://visitsweden.fr/larchipel-de-stockholm-un-petit-coin-de-paradis-visiter/</a></li>
<li><a href="https://www.marguerite-et-troubadour.fr/de-stockholm-a-grinda/">https://www.marguerite-et-troubadour.fr/de-stockholm-a-grinda/</a></li>
</ul>
<p>En revenant à Stockholm, on a voulu aller au <a href="https://www.openstreetmap.org/way/24968329">National
Museet</a> mais celui-ci était en
travaux jusqu’en octobre 2018. On a donc été au <a href="https://www.openstreetmap.org/node/29898032">Moderna
Museet</a>, le musée d’art moderne
de la ville. Les collections permanentes sont gratuites. Il y avait une
exposition temporaire gratuite, <a href="https://arkdes.se/en/utstallning/public-luxury/">Public
Luxury</a> top sur le design et
l’urbanisme, et une exposition temporaire sur Warhol (entrée à 100 <span class="caps">SEK</span>, 70 <span class="caps">SEK</span>
en tarif réduit).</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j11/DSC07938.JPG" title="National Museet">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j11_mini/DSC07938.JPG"
style="max-width: 50%"
alt="National Museet" />
</a>
</p>
<p>Le soir, on est allé manger chez <a href="https://www.openstreetmap.org/node/1778361756">Sjatte
Tunnan</a>, un restaurant ambiance
médiévale dans une cave de Gamla Stan. L’ambiance est super, avec les serveurs
et serveuses en costume, des cartes en parchemin et des couverts étranges
(couteau et cuillère seulement). Il y a un grand choix de bières, d’hydromel
et de cidres. Les plats sont copieux et très bons avec (comme toujours) des
options végétariennes. Compter 10-15 € pour les entrées et 20-30 € pour les
plats. On recommande particulièrement le saumon (Spicken Lax) en entrée, les
boulettes d’élan aux airelles et la pintade. Sachez que si vous êtes
suffisamment nombreux, vous pouvez opter pour l’option “festin” où on vous
préparera un cochon de lait entier pour vous et vous l’amèneront à table !
:) Réservation recommandée. Il vaut mieux réserver par téléphone plutôt que
par leur site internet visiblement (ielles ne centralisent pas leurs
réservations et le cahier est géré en priorité).</p>
<h2>12e jour, le palais royal et retour en France</h2>
<p>Petite découverte par hasard ce dernier jour, tôt le matin (surtout) et tard
le soir (en-dehors des grandes artères), il n’y a pas grand monde dans Gamla
Stan. Pour faire de belles photos sans les touristes, il faut donc viser d’y
passer vers 8h ou 9h ! :)</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j12/DSC08073.JPG" title="Les appartements royaux">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j12_mini/DSC08073.JPG"
style="max-width: 50%"
alt="Les appartements royaux" />
</a>
</p>
<p>Pour ce dernier jour, on a visité le <a href="https://www.openstreetmap.org/relation/34394#map=18/59.32690/18.07168&layers=N">Palais
Royal</a>
(entrée à 160 ou 180 <span class="caps">SEK</span> selon si on prend l’entrée à la
<a href="https://www.openstreetmap.org/way/23841420">Riddarholmskyrkan</a> aussi ou non,
80 ou 90 <span class="caps">SEK</span> en tarif réduit pour les étudiants ou les mineurs). On peut
prendre une visite guidée pour 20 <span class="caps">SEK</span> de plus. Bien vérifier les horaires et
les ouvertures du palais en ligne avant d’y aller car certaines ailes peuvent
être fermées lors de réceptions officielles. L’extérieur est actuellement en
cours de restauration, mais l’intérieur est superbe ! La Riddarholmskyrkan est
l’église où sont les tombeaux des membres de la famille royale. On y trouve
aussi les blasons de toutes les personnes décorées de <a href="https://fr.wikipedia.org/wiki/Ordre_des_S%C3%A9raphins">l’ordre des
Séraphins</a> (dont le
Général de Gaulle et François Mitterand).</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j12/DSC08079.JPG" title="Riddarholmskyrkan">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j12_mini/DSC08079.JPG"
style="max-width: 50%"
alt="Riddarholmskyrkan" />
</a>
</p>
<p>Il y a pas mal d’explications et de textes à lire dans les différentes salles
et toute l’aile des appartements Bernadotte a un audioguide gratuit donc la
visite guidée n’est pas essentielle. Compter 1h30 en tout pour visiter
l’intérieur des appartements royaux et Bernadotte. Le billet donne ensuite le
droit de visiter le <a href="https://www.openstreetmap.org/node/304607835">Musée Tre
Kronor</a>, un petit musée
d’archéologie qui est loin d’être le plus intéressant dans le billet. Il
permet de voir les sous-sols. Il y a aussi un <a href="https://www.openstreetmap.org/node/1815123227">Musée
d’Antiquités</a> qui est fermé à
cette période. La <a href="https://www.openstreetmap.org/node/1243683380">chapelle
royale</a> était fermée aussi.</p>
<p>De l’autre côté du palais, ne pas rater le
<a href="https://www.openstreetmap.org/node/304606190">Livrustkammaren</a>, un musée
gratuit qui expose des costumes et surtout de nombreux (et magnifiques)
carrosses d’époque. Il y a aussi un autre étage d’exposition (permanente)qui
était fermé jusqu’en 2019.</p>
<p>Enfin, ne pas rater <a href="https://www.openstreetmap.org/node/2106971722">le trésor
royal</a> (inclus dans le billet
du palais) avec de magnifiques bijoux et couronnes !</p>
<p>Il y a une relève de la garde entre 12h45 et 13h15 (les horaires précis ainsi
que le trajet est affiché devant la billetterie du palais). La garde part en
général du <a href="https://www.openstreetmap.org/node/289851448">Musée de l’Armée</a>
puis passe devant le
<a href="https://www.openstreetmap.org/relation/34395#map=19/59.32767/18.06806&layers=N">Parlement</a>
avant de faire le tour du château et de finir dans la <a href="https://www.openstreetmap.org/way/38685227">cour
d’honneur</a>. Tout le trajet se fait
en fanfare et la garde est mixte (et pas loin de la parité) !</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j12/DSC08091.JPG" title="La relève de la garde">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j12_mini/DSC08091.JPG"
style="max-width: 50%"
alt="La relève de la garde" />
</a>
</p>
<p>Sur la place du palais royal, vous pouvez aussi visiter la
<a href="https://www.openstreetmap.org/way/8049504">Storkyrkan</a> (la cathédrale, entrée
à 60 <span class="caps">SEK</span>, 50 <span class="caps">SEK</span> en tarif réduit).</p>
<p>Dans Gamla Stan, ne pas manquer non plus la très belle <a href="https://www.openstreetmap.org/way/8049509">Tyska
kyrkan</a> (église allemande). On peut
rentrer pour voir gratuitement derrière une petite rembarde mais si vous
voulez faire tout le tour de l’église il faudra payer 30 <span class="caps">SEK</span> (20 <span class="caps">SEK</span> en tarif réduit).</p>
<p>Finalement, c’est l’heure du retour à Paris, en avion avec Norwegian, de
Stockholm Arlanda à Paris Orly, en fin de journée. Les billets étaient à
55 €
par personne, pas grand chose en comparaison du train… :/</p>
<p>Pour rejoindre l’aéroport, le plus simple est de prendre l’<a href="https://www.arlandaexpress.com/">Arlanda
Express</a>, un train rapide (il roule à 200
km/h !) qui relie la <a href="https://www.openstreetmap.org/node/412207994">gare
centrale</a> à l’aéroport en 20
minutes (± 5 minutes, sinon ils vous offrent un autre billet). Les billets
sont assez chers mais il est possible d’avoir des tarifs
assez raisonnables en réservant à l’avance (jusqu’à 90 jours !) ou en prenant
des billets doubles (2 personnes pour 350 <span class="caps">SEK</span> le weekend, pas besoin de les
prendre en avance). Pour les jeunes (25 ans ou moins) et les étudiants (carte
<span class="caps">ISIC</span> requise), le plus rentable est de prendre un billet étudiant ou jeune (au
guichet, forcément, mais il n’y a pas de queue).</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j12/DSC08107.JPG" title="Arlanda Express">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j12_mini/DSC08107.JPG"
style="max-width: 50%"
alt="Arlanda Express" />
</a>
</p>
<p>Norwegian est une compagnie <em>low cost</em> mais est plutôt dans le haut du panier
(sensiblement comme EasyJet, un cran au-dessus de Vueling / Transavia / Ryan
Air / …). Il y a le wifi gratuit dans l’avion.</p>
<p style="text-align: center;">
<a href="http://localhost/Blog/output/images/2018/10/suede_en_train/j12/DSC08109.JPG" title="Norwegian">
<img
src="http://localhost/Blog/output/images/2018/10/suede_en_train/j12_mini/DSC08109.JPG"
style="max-width: 50%"
alt="Norwegian" />
</a>
</p>
<p><strong>Note</strong> : Petite astuce pour Norwegian : ils incitent fortement à mettre son
bagage cabine en soute car comme dans tous les <em>low costs</em>, il n’y a pas assez
de place pour tous les bagages cabines à bord. Il y a des annonces dès
l’enregistrement pour vous y inciter mais il vaut mieux attendre
l’embarquement. À l’embarquement, on vous proposera d’embarquer parmi les
premiers si vous acceptez de mettre (gratuitement) votre bagage cabine en soute.</p>
<h2>Quelques outils utiles</h2>
<ul>
<li>Pour les trains, les sites des diverses compagnies :
<a href="https://www.oui.sncf/"><span class="caps">SNCF</span></a>, <a href="https://www.thalys.com/">Thalys</a>,
<a href="https://www.bahn.de/p/view/index.shtml"><span class="caps">DB</span></a> et <a href="http://sj.se/"><span class="caps">SJ</span></a>. En
France et en Belgique, <a href="http://trainline.eu/">Trainline</a> est plus agréable
à utiliser et devrait vous éviter des déconvenues avec un billet français
en Belgique (voir plus haut). En Allemagne, mieux vaut acheter directement
auprès de la <span class="caps">DB</span> pour être notifié des modifications sur votre train (voir
plus haut).</li>
<li>La page du parcours Paris - Copenhague sur <a href="https://www.lemondeentrain.fr/paris-copenhague-en-train.html">le monde en
train</a>, avec
tous les détails et les horaires a priori à jour.</li>
<li>En Scanie, les transports régionaux sont sur <a href="https://www.skanetrafiken.se/">ce
site</a> (étonnamment très dur à retrouver avec
une recherche sur internet). Il y a une application aussi et les trains
sont aussi listés par <span class="caps">SJ</span>.</li>
<li>L’application <span class="caps">SJ</span>, très pratique.</li>
<li><a href="https://www.vasttrafik.se/en/tickets/more-about-tickets/vasttrafik-to-go/">L’application
Västtrafik</a>
pour payer moins cher ses billets de transport et ne pas s’embêter à
trouver où acheter des billets papier.</li>
<li><a href="http://osmand.net/">OsmAnd</a> pour télécharger des cartes
<a href="http://openstreetmap.org/"><span class="caps">OSM</span></a> en local et toujours les avoir à portée
de main. Bien pratique !</li>
</ul>
<h2>Quelques notes en vrac</h2>
<h3>Général</h3>
<ul>
<li>Globalement, on a eu une météo superbe avec seulement un jour de pluie et
deux jours de gris, pour une fin septembre / début octobre. On avait
regardé en avance et la météo avait l’air assez raisonnable à cette saison
(par contre, il a fait bien plus chaud que prévu).</li>
<li>En-dehors de France, on trouve vraiment des consignes à bagages partout. On
en a toujours trouvé dans les gares (Bruxelles, Cologne, Hambourg et
Copenhague), acceptant principalement les espèces (et quelques rares fois
les CBs). En Suède, il semble y en avoir dans toutes les gares (on en a
vu à Malmö, Göteborg, Lund, Helsingborg, Stockholm), acceptant souvent les
CBs et les espèces.</li>
<li>En Suède, dans les musées, il y a quasiment systématiquement des petits
casiers pour les sacs et vêtements (gratuits, ou on vous donne un jeton à
l’accueil). Bien pratique pour visiter le musée léger !</li>
<li>En Suède et au Danemark, les musées et les commerces ferment tôt
(18h / 19h grand maximum). Les supermarchés ont par contre très souvent
des horaires d’ouverture très larges (7h - 23h n’est pas très rare par
exemple). Les cafés et autres endroits pour manger pour pas très cher
ferment souvent tôt (18h / 19h maximum), pas très pratique pour le soir du
coup. Attention à organiser votre journée en fonction ! :)</li>
<li>La Suède est à la pointe pour les régimes particuliers. Tous les allergènes
sont systématiquement indiqués et il y a quasiment partout des menus
adaptés pour les végétariens et les végétaliens.</li>
<li>La Suède et le Danemark sont aussi nettement plus au point que nous sur
l’accessibilité des lieux. En vrac, les lieux sont souvent adaptés, il y a
quasiment systématiquement des toilettes adaptées. Sur les aires de
fitness, on a vu plusieurs fois des indications d’exercice réalisables en
fauteuil. Tous les feux tricolores font tutut pour indiquer quand
traverser. À Drottningolm, on a même vu un plan des jardins du château
avec toutes les pentes de plus de 5% indiquées en rouge.</li>
<li>En Allemagne, Danemark et Suède, tout le monde parle (très bien) anglais,
souvent mieux que nous…</li>
<li>À Stockholm, tous les WCs publics sont payants. Ailleurs, c’est variable. En
Belgique et en Allemagne, les WCs sont très souvent payants. Dans les
gares, les WCs sont payants quasiment systématiquement.</li>
<li>Au Danemark et en Suède, énormément de choses sont faites pour les enfants.
On trouve des coins dédiés avec des jeux dans tous les musées (et dans les
églises !). Dans les WCs (genrés hommes <em>et</em> femmes), on trouve
systématiquement des tables à langer aussi.</li>
<li>Le 4 octobre, c’est la <a href="https://fr.wikipedia.org/wiki/Kanelbullens_dag">fête des
kanelbullars</a> en Suède
(une raison de plus d’en manger plein :) !!!</li>
<li>On trouve énormément de pistes cyclables (et on voit énormément de cyclistes
!) dans les pays qu’on a traversé. J’ai fait un fil de tout ce que j’ai vu
<a href="https://mastodon.tetaneutral.net/@Phyks/100797791222000159">sur
Mastodon</a>.</li>
<li>On a vu d’étranges feux piétons doubles à Cologne, Hambourg et Copenhague.
Visiblement, c’est pour dissuader les piétons de traverser au rouge.</li>
<li>À Stockholm, <a href="http://citymapper.com/">CityMapper</a> peut être bien pratique
pour chercher des itinéraires en transport en commun, mais il n’est
carrément pas au point sur les déviations temporaires. À utiliser avec
méfiance donc (en particulier du côté de Slussen qui est un chantier à
ciel ouvert en ce moment).</li>
<li>En Suède et au Danemark, il n’y a pas les euros (mais les couronnes
suédoises et danoises). Étudiez bien les conditions de votre carte bleue à
l’étranger avant de partir (la mienne me coûte minimum 2 € de frais de
change par transaction…). Dans ce cas, ouvrir un compte chez une banque en
ligne comme <a href="https://n26.com/fr-fr">N26</a> peut être très vite intéressant.</li>
<li>On était parti avec deux guides touristiques, le <a href="http://www.guides-hachette.fr/livre/guide-du-routard-danemark-suede-201718-9782012799363">Routard Danemark /
Suède</a>
et le <a href="https://www.lonelyplanet.fr/catalogue/suede-4ed">Lonely Planet
Suède</a> (merci la
bibliothèque municipale ! :). Le Routard était globalement plus complet et
mieux pour les visites mais le Lonely avait souvent plus de conseils de
cafés et restaurants, ils sont donc assez complémentaires.</li>
</ul>
<h3>Sur les trains</h3>
<ul>
<li>Il est possible de prendre un <a href="https://www.interrail.eu/fr/pass-interrail/global-pass">Pass
InterRail</a> pour le
trajet. C’est à voir au cas par cas mais en s’y prenant à l’avance avec
des cartes jeunes, ce n’était pas rentable pour nous.</li>
<li><a href="http://sj.se/"><span class="caps">SJ</span></a> a une application mobile très bien faite, très complète
et qui vous guide jusqu’au bon emplacement sur le quai avec votre <span class="caps">GPS</span> :)
Globalement, le site de <span class="caps">SJ</span> est un des plus agréables à utiliser, il
marche bien, on peut choisir sa place comme dans les avions à la
réservation et les billets ne sont pas très chers ! <span class="caps">SJ</span> a même une page
avec des infos détaillées sur <a href="https://www.sj.se/en/about/about-sj/our-trains.html">leurs
trains</a>.</li>
<li>Les <span class="caps">SJ3000</span> (notre Malmö - Göteborg) sont vraiment top, même en seconde
classe. Les sièges sont très larges, il y a une prise par personne et un
repose bagage entre la fenêtre et le siège côté fenêtre. Wifi dans le train.</li>
<li>Les X2000 (notre Göteborg - Malmö) sont un peu moins bien, décevants en
comparaison :p On a eu un changement de direction étrange à Göteborg et
notre place dans le sens de la marche s’est retrouvée être dans le sens
inverse finalement… tout n’est pas parfait.</li>
<li>En Scanie et entre la Scanie et le Danemark, les trains circulent de façon
très régulière et quasiment 24h/24.</li>
<li>On n’a jamais eu aucun contrôle de billet en Suède dans les trains grande
vitesse (mais dans les trains en Scanie, oui).</li>
<li>Une liaison Paris - Copenhague est possible par train de nuit, mais
seulement l’été (en tout cas, elle n’existait pas quand on a réservé).
Voir chez
<a href="http://www.seat61.fr/Paris-Copenhague-Danemark-en-train.htm#by%20Thalys">seat61</a>
ou <a href="https://www.lemondeentrain.fr/paris-copenhague-en-train.html">lemondeentrain</a>.</li>
<li>Les trains qu’on a pris au Danemark et en Suède n’avaient pas de motrice, mais
un premier wagon qui faisait locomotive aussi. Étrange…</li>
<li>Visiblement il y a une loi en Suède qui dit que<ul>
<li>si un transport a plus de 20 minutes de retard avant le départ, on est
indemnisé de 100 € maximum pour prendre un transport alternatif.
Valable aussi si on n’a pas encore acheté le billet (le prix du billet
est alors déduit de la compensation).</li>
<li>si un transport a du retard en cours de trajet, on doit vous rembourser
le billet à hauteur de 50% (au moins 20 minutes de retard), 75% (au
moins 40 minutes) ou 100% (au moins une heure).</li>
</ul>
</li>
<li>On n’avait jamais fait de trajets aussi longs en train et on appréhendait un
peu. Finalement, on n’a pas vu les trajets passer ! Le train faisait une
pause agréable pour planifier les journées suivantes. C’est en tout cas
bien plus agréable que des trajets aussi longs en voiture comme on a pu
le faire par le passé. On ne se rend pas forcément compte non plus mais
un trajet de 5h en train, c’est 5h assis dans un train tranquillement à
pouvoir faire des choses. Par comparaison, pour notre vol retour, on est
parti à 15h de la gare de Stockholm et on a atterri à 22h à Paris, ce qui
fait 7h de trajet total pour seulement 2h30 de vol “tranquille”.</li>
</ul>
<p>Si vous n’avez pas de compte chez :</p>
<ul>
<li>Airbnb, vous pouvez utiliser <a href="https://www.airbnb.fr/c/lverney3">ce lien</a>
pour créer un compte : 25 € de crédit offert à utiliser sur votre première
réservation (et je gagne 15 € de crédit pour un prochain voyage une fois
votre premier voyage effectué).</li>
<li>Booking, vous pouvez utiliser <a href="https://booking.com/s/39_0/mfouil80">ce lien</a>
pour créer un compte : 25$ de crédit offert sur votre première réservation
de 50$ minimum, ça marche aussi avec des euros et les gains sont juste à
adapter avec le taux de change (et je gagne la même chose pour un prochain
voyage une fois votre premier voyage effectué).</li>
</ul>
<p>J’espère que ces conseils vous aideront à préparer votre prochain séjour !
N’hésitez pas à me faire part de commentaires ou suggestions !</p>
<p>Cet article est sous licence <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons
<span class="caps">BY</span>-<span class="caps">NC</span>-<span class="caps">SA</span></a>. N’hésitez pas à
le repartager et à le modifier à votre convenance, tout en gardant un lien
vers le document original, et en conservant la même licence, le tout pour une
visée non commerciale.</p>Cycl’Assist 0.3 is out!2018-10-22T11:00:00+02:002018-10-22T11:00:00+02:00Phykstag:localhost,2018-10-22:/Blog/output/2018/10/cyclassist-03-is-out.html<p><a href="https://framagit.org/phyks/cyclassist">Cycl’Assist</a> aims to be a webapp
to ease tracking and reporting issues with bike infrastructures while riding
your bike (any danger on the way such as holes in the ground, cars parked like
sh*t, road work, etc). You can think of it as Waze for bikes :) Version 0 …</p><p><a href="https://framagit.org/phyks/cyclassist">Cycl’Assist</a> aims to be a webapp
to ease tracking and reporting issues with bike infrastructures while riding
your bike (any danger on the way such as holes in the ground, cars parked like
sh*t, road work, etc). You can think of it as Waze for bikes :) Version 0.3 is
now out and live at <a href="https://cyclo.phyks.me/">https://cyclo.phyks.me/</a>! Here is
a list of the main new features.</p>
<h2>Speed badge</h2>
<p>First of all, this new version now features a speed badge so you can get an
estimate of your current speed. Speed is provided by the <span class="caps">GPS</span> interface so it is
only displayed if you enabled geolocation. Note that this speed might not
accurately reflect your current speed (especially at low speed or in urban
areas) due to the way it is acquired from <span class="caps">GPS</span> data.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/10/cyclassist_speed.png">
<img
style="max-width: 800px; max-height: 600px"
src="http://localhost/Blog/output/images/2018/10/cyclassist_speed.png"
alt="New speed badge in Cycl'Assist" />
</a>
</p>
<h2>Permanent notification</h2>
<p>This version introduces a new setting to display a permanent notification
whenever Cycl’Assist is running in a tab. If you move to another tab or change
app on your phone, you can click the notification at any time to be sent back
to the new report window and send a report at your current location!</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/10/cyclassist_notification.png">
<img
style="max-width: 800px; max-height: 600px"
src="http://localhost/Blog/output/images/2018/10/cyclassist_notification.png"
alt="Permanent notification of Cycl'Assist" />
</a>
</p>
<h2>Importing OpenData about roadworks</h2>
<p>Quite a lot of cities and local administrations around France are providing
OpenData for roadworks. This is the case for:</p>
<ul>
<li><a href="https://opendata.lillemetropole.fr/explore/dataset/troncons-de-voirie-impactes-par-des-travaux-en-temps-reel/">Lille</a>,</li>
<li>the <a href="https://open-loiret.opendata.arcgis.com/datasets/74c95548589d4ddeb3fcf094f7d61a67_1?geometry=0.609%2C47.694%2C3.245%2C48.016&orderBy=BLOCKNM">Département du Loiret</a></li>
<li>the <a href="https://data.grandlyon.com/equipements/chantiers-perturbants-de-la-mftropole-de-lyon/">Métropole de Lyon</a></li>
<li><a href="http://data.montpellier3m.fr/dataset/chantiers-genants-de-montpellier">Montpellier Méditerranée Métropole</a></li>
<li>the <a href="http://opendata.grandnancy.eu/jeux-de-donnees/detail-dune-fiche-de-donnees/?tx_icsoddatastore_pi1%5Bkeywords%5D=travaux&tx_icsoddatastore_pi1%5Buid%5D=63&tx_icsoddatastore_pi1%5BreturnID%5D=447">Grand Nancy</a></li>
<li><a href="https://opendata.paris.fr/explore/dataset/chantiers-perturbants/">Paris</a></li>
<li><a href="http://travaux.data.rennesmetropole.fr/">Rennes Métropole</a></li>
<li>the <a href="https://geo.data.gouv.fr/fr/datasets/12504debb9bb73e717ad710a746541ebf817d98c">Département de la Seine-Saint-Denis</a></li>
<li><a href="https://data.opendatasoft.com/explore/dataset/travauxincidents@sicoval-haute-garonne/">Sicoval</a> (South-East of Toulouse)</li>
<li><a href="https://data.toulouse-metropole.fr/explore/dataset/chantiers-en-cours/">Toulouse Métropole</a></li>
<li>Versailles Grand Parc which has three different datasets: <a href="http://www-cavgp.opendata.arcgis.com/datasets/f58091424f38424ba04a2d3933dc979e_0">Road
Blocks</a>,
<a href="https://www-cavgp.opendata.arcgis.com/datasets/f58091424f38424ba04a2d3933dc979e_1">Road
Closures</a>
and <a href="https://www-cavgp.opendata.arcgis.com/datasets/f58091424f38424ba04a2d3933dc979e_2">Road Detours</a></li>
</ul>
<p>Note that this list might not be exhaustive but these are all the roadworks
OpenData I could gather in metropolitan France so far. All of these are now
imported on a daily basis on <a href="https://cyclo.phyks.me/">https://cyclo.phyks.me/</a>.
Feel free to reuse <a href="https://framagit.org/phyks/cyclassist/blob/master/scripts/opendata/works.py">the OpenData import
script</a>
for your own projects!</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/10/cyclassist_roadworks.png">
<img
style="max-width: 800px; max-height: 600px"
src="http://localhost/Blog/output/images/2018/10/cyclassist_roadworks.png"
alt="Cycl'Assist now features opendata roadworks" />
</a>
</p>
<h2>Faster loading</h2>
<p>Cycl’Assist is meant to be mostly used on the go, on your phone. Then, you
might not always have the best mobile connection available. Cycl’Assist is
doing its best to perform well even if you are running on a slow 3G conection.
In this version, some work was done to reduce the weight of the webpage while
providing always more features. For the developers interested in this part, I
wrote another <a href="https://phyks.me/2018/09/reduce-webapp-build-size.html#reduce-webapp-build-size">blog
post</a>
a month ago :)</p>
<p>The app should also perform better generally through small enhancements such
as keeping only the nearby reports to avoid loading the memory of the device
too much.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/10/cyclassist_loading.png">
<img
style="max-width: 800px; max-height: 600px"
src="http://localhost/Blog/output/images/2018/10/cyclassist_loading.png"
alt="Cycl'Assist performance score in LightHouse" />
</a>
</p>
<h2>For the developers, an enhanced <span class="caps">API</span></h2>
<p>This new version comes with an enhanced <span class="caps">API</span> with some filtering capabilities.
In particular, you can now export all reports from a given geographical
bounding box using an <span class="caps">API</span> call to</p>
<div class="highlight"><pre><span></span><code><span class="o">></span><span class="w"> </span><span class="k">GET</span><span class="w"> </span><span class="nl">https</span><span class="p">:</span><span class="o">//</span><span class="n">cyclo</span><span class="p">.</span><span class="n">phyks</span><span class="p">.</span><span class="n">me</span><span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">v1</span><span class="o">/</span><span class="n">reports</span><span class="vm">?</span><span class="k">filter</span><span class="o">[</span><span class="n">lat</span><span class="o">][</span><span class="n">gt</span><span class="o">]=</span><span class="n">LAT_MIN</span><span class="o">&</span><span class="k">filter</span><span class="o">[</span><span class="n">lat</span><span class="o">][</span><span class="n">lt</span><span class="o">]=</span><span class="n">LAT_MAX</span><span class="o">&</span><span class="k">filter</span><span class="o">[</span><span class="n">lng</span><span class="o">][</span><span class="n">gt</span><span class="o">]=</span><span class="n">LNG_MIN</span><span class="o">&</span><span class="k">filter</span><span class="o">[</span><span class="n">lng</span><span class="o">][</span><span class="n">lt</span><span class="o">]=</span><span class="n">LNG_MAX</span>
</code></pre></div>
<p>For instance,
<a href="https://cyclo.phyks.me/api/v1/reports?filter[lat][gt]=48.8092&filter[lat][lt]=48.9084&filter[lng][gt]=2.2186&filter[lng][lt]=2.4753">here</a>
is an extract of all reports around Paris. The full <span class="caps">API</span> documentation is
available
<a href="https://framagit.org/phyks/cyclassist/blob/master/doc/20.api.md">here</a>.</p>
<h2>And some minor bug fixing and few small enhancements</h2>
<ul>
<li>Upvotes on <span class="caps">GCUM</span> (poorly parked) cars now reset the expiration delay.</li>
<li>There was a bug in the manual address selection when it would sometimes not
send you to the picked location. This is now fixed.</li>
<li>Sometimes the tips of the markers was slightly off, this is now fixed and
the tips of the markers should point to the exact location of the report.</li>
<li><a href="https://framagit.org/phyks/cyclassist/tree/master/doc">More documentation</a>
has been written.</li>
<li>Still available in English, French and Occitan (thanks to
<a href="https://framapiaf.org/@Quenti">@Quenti</a>)!</li>
</ul>Reduce webapp build size2018-09-11T19:00:00+02:002018-09-11T19:00:00+02:00Phykstag:localhost,2018-09-11:/Blog/output/2018/09/reduce-webapp-build-size.html<p>I recently started working on
<a href="https://framagit.org/phyks/cyclassist">Cyclassist</a> which aims to be a webapp
to ease tracking and reporting issues with bike infrastructures while riding
your bike (any danger on the way such as holes in the ground, cars parked like
shit, road work, etc). You can think of it as Waze …</p><p>I recently started working on
<a href="https://framagit.org/phyks/cyclassist">Cyclassist</a> which aims to be a webapp
to ease tracking and reporting issues with bike infrastructures while riding
your bike (any danger on the way such as holes in the ground, cars parked like
shit, road work, etc). You can think of it as Waze for bikes :)</p>
<p>This webapp is meant to be used while riding your bike, on the go. Then, I
wanted it to be as small as possible, to ensure the first render on a mobile
device will be quick and the whole app will be downloaded as fast as possible.
I came across <a href="https://www.smashingmagazine.com/2017/08/removing-friction-ux-last-minute-travel-planning-activity-booking/">this Smashing Magazine
article</a>
which gives some rough ideas and was really inspiring.</p>
<p>Documentation on reducing the build size is really scattered around the web
and I did not find any comprehensive guide of the best steps to take to reduce
a webapp built files size. Here is a tour of the steps I took, using
Cycl’Assist to provide examples.</p>
<p>I am starting from a webapp with two chunks: a “vendor” chunk (everything from
<code>node_modules</code>) which is around 190 kB (after gzip) and an app chunk which is
around 25 kB (after gzip). This corresponds to <a href="https://framagit.org/phyks/cyclassist/commit/d5dcf96af82bdf74d97429292014c74b6f2007d6">this
commit</a>.
Note that at this time I was using the <a href="https://github.com/vuetifyjs/webpack">Vuetify webpack
template</a> so part of the optimizations
listed below were already included. Production build time (for reference) is
70 s.</p>
<p><em>Note:</em> This is a <a href="https://vuejs.org/">Vue</a> + <a href="http://vuetifyjs.com/">Vuetify</a>
webapp so some comments and code might be tailored for this setup. However,
the ideas behind are general and could be adapted to other codebases :)
Webpack 4 is used.</p>
<h2>Bundle analyzer</h2>
<p>First, the best way to check what is included in your bundles and the weight
of each included lib is to use
<a href="https://github.com/webpack-contrib/webpack-bundle-analyzer#usage-as-a-plugin">Webpack-bundle-analyzer</a>.</p>
<p>To use it, simply put something like this in your production Webpack config</p>
<div class="highlight"><pre><span></span><code><span class="kd">const</span><span class="w"> </span><span class="nx">webpackConfig</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="err">…</span><span class="w"> </span><span class="p">};</span>
<span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">ANALYZE</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="kd">const</span><span class="w"> </span><span class="nx">BundleAnalyzerPlugin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">require</span><span class="p">(</span><span class="s1">'webpack-bundle-analyzer'</span><span class="p">).</span><span class="nx">BundleAnalyzerPlugin</span>
<span class="w"> </span><span class="nx">webpackConfig</span><span class="p">.</span><span class="nx">plugins</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="ow">new</span><span class="w"> </span><span class="nx">BundleAnalyzerPlugin</span><span class="p">())</span>
<span class="p">}</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">webpackConfig</span><span class="p">;</span>
</code></pre></div>
<p>You can now run your production build command with <code>ANALYZE=true</code> prepended to
open a browser window at the end of the build process pointing to the bundle
analyzer result.</p>
<h2>Extract <span class="caps">CSS</span> to a dedicated file</h2>
<p>Then, you can extract the <span class="caps">CSS</span> into a dedicated <span class="caps">CSS</span> file rather than having it
together with your <span class="caps">JS</span> code. This can be done using a config similar to</p>
<div class="highlight"><pre><span></span><code><span class="kd">const</span><span class="w"> </span><span class="nx">MiniCssExtractPlugin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nx">require</span><span class="p">(</span><span class="s2">"mini-css-extract-plugin"</span><span class="p">);</span>
<span class="nx">module</span><span class="p">.</span><span class="nx">exports</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="err">…</span><span class="p">,</span>
<span class="w"> </span><span class="nx">module</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">rules</span><span class="o">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">test</span><span class="o">:</span><span class="w"> </span><span class="sr">/\.css$/</span><span class="p">,</span>
<span class="w"> </span><span class="nx">use</span><span class="o">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="c1">// In development, use regular vue-style-loader. In</span>
<span class="w"> </span><span class="c1">// production, use the MiniCssExtract loader to extract CSS to</span>
<span class="w"> </span><span class="c1">// a dedicated file.</span>
<span class="w"> </span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NODE_ENV</span><span class="w"> </span><span class="o">!==</span><span class="w"> </span><span class="s1">'production'</span>
<span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="s1">'vue-style-loader'</span>
<span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="nx">MiniCssExtractPlugin</span><span class="p">.</span><span class="nx">loader</span><span class="p">,</span>
<span class="w"> </span><span class="c1">// Process with other loaders, namely css-loader and</span>
<span class="w"> </span><span class="c1">// postcss-loader.</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">loader</span><span class="o">:</span><span class="w"> </span><span class="s1">'css-loader'</span><span class="p">,</span>
<span class="w"> </span><span class="c1">// PostCSS is run before, see</span>
<span class="w"> </span><span class="c1">// https://github.com/webpack-contrib/css-loader#importloaders</span>
<span class="w"> </span><span class="nx">options</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">importLoaders</span><span class="o">:</span><span class="w"> </span><span class="mf">1</span><span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">loader</span><span class="o">:</span><span class="w"> </span><span class="s1">'postcss-loader'</span><span class="p">,</span>
<span class="w"> </span><span class="nx">options</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">plugins</span><span class="o">:</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">[</span><span class="nx">require</span><span class="p">(</span><span class="s2">"postcss-preset-env"</span><span class="p">)()],</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">test</span><span class="o">:</span><span class="w"> </span><span class="sr">/\.styl(us)?/</span><span class="p">,</span>
<span class="w"> </span><span class="nx">use</span><span class="o">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="c1">// Same loader hierarchy for stylus files (used by Vuetify).</span>
<span class="w"> </span><span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">NODE_ENV</span><span class="w"> </span><span class="o">!==</span><span class="w"> </span><span class="s1">'production'</span>
<span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="s1">'vue-style-loader'</span>
<span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="nx">MiniCssExtractPlugin</span><span class="p">.</span><span class="nx">loader</span><span class="p">,</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">loader</span><span class="o">:</span><span class="w"> </span><span class="s1">'css-loader'</span><span class="p">,</span>
<span class="w"> </span><span class="nx">options</span><span class="o">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">importLoaders</span><span class="o">:</span><span class="w"> </span><span class="mf">1</span><span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">loader</span><span class="o">:</span><span class="w"> </span><span class="s1">'postcss-loader'</span><span class="p">,</span>
<span class="w"> </span><span class="nx">options</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Assumes you have a</span>
<span class="w"> </span><span class="c1">// [browserslist](https://github.com/browserslist/browserslist#readme)</span>
<span class="w"> </span><span class="c1">// in a config file or as a package.json entry</span>
<span class="w"> </span><span class="nx">plugins</span><span class="o">:</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">[</span><span class="nx">require</span><span class="p">(</span><span class="s2">"postcss-preset-env"</span><span class="p">)()],</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="s1">'stylus-loader'</span><span class="p">,</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="nx">plugins</span><span class="o">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">MiniCssExtractPlugin</span><span class="p">({</span>
<span class="w"> </span><span class="nx">filename</span><span class="o">:</span><span class="w"> </span><span class="nx">utils</span><span class="p">.</span><span class="nx">assetsPath</span><span class="p">(</span><span class="s1">'css/[name].[contenthash:4].css'</span><span class="p">),</span>
<span class="w"> </span><span class="nx">chunkFilename</span><span class="o">:</span><span class="w"> </span><span class="nx">utils</span><span class="p">.</span><span class="nx">assetsPath</span><span class="p">(</span><span class="s1">'css/[name].[contenthash:4].css'</span><span class="p">),</span>
<span class="w"> </span><span class="p">}),</span>
<span class="w"> </span><span class="p">]</span>
<span class="p">};</span>
</code></pre></div>
<p><em>Note:</em> You should define your <code>browserslist</code> entry according to your own
specs and typical client browsers. You can use
<a href="http://browserl.ist/">browserl.ist</a> to check which browsers are included.</p>
<p>Note that we use hash in the generated <span class="caps">CSS</span> file for easy management of <a href="https://www.keycdn.com/support/what-is-cache-busting/">cache
bustingi</a>. Whenever the
content of the file changes, the <code>contenthash</code> will change and this ensures
the updated file will be indeed requested at next visit as the <span class="caps">URL</span> will be different.</p>
<h2>Minify everything</h2>
<h3>UglifyJS and OptimizeCSSAssets</h3>
<p>Then, we want to minify <span class="caps">JS</span> and <span class="caps">CSS</span> as much as possible. This can be done using
<a href="https://github.com/webpack-contrib/uglifyjs-webpack-plugin"><code>UglifyJS</code></a> and
<a href="https://github.com/NMFR/optimize-css-assets-webpack-plugin"><code>OptimizeCSSAssets</code></a>
plugins. For example,</p>
<div class="highlight"><pre><span></span><code><span class="k">const</span><span class="w"> </span><span class="n">OptimizeCSSAssetsPlugin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">require</span><span class="p">(</span><span class="s2">"optimize-css-assets-webpack-plugin"</span><span class="p">);</span>
<span class="k">const</span><span class="w"> </span><span class="n">UglifyJsPlugin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">require</span><span class="p">(</span><span class="s1">'uglifyjs-webpack-plugin'</span><span class="p">)</span>
<span class="n">module</span><span class="o">.</span><span class="n">exports</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="err">…</span><span class="p">,</span>
<span class="w"> </span><span class="n">optimization</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">minimizer</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="n">new</span><span class="w"> </span><span class="n">UglifyJsPlugin</span><span class="p">({</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Enable</span><span class="w"> </span><span class="n">file</span><span class="w"> </span><span class="n">caching</span>
<span class="w"> </span><span class="n">cache</span><span class="p">:</span><span class="w"> </span><span class="bp">true</span><span class="p">,</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Use</span><span class="w"> </span><span class="n">multiprocess</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">improve</span><span class="w"> </span><span class="n">build</span><span class="w"> </span><span class="n">speed</span>
<span class="w"> </span><span class="n">parallel</span><span class="p">:</span><span class="w"> </span><span class="bp">true</span>
<span class="w"> </span><span class="p">}),</span>
<span class="w"> </span><span class="n">new</span><span class="w"> </span><span class="n">OptimizeCSSAssetsPlugin</span><span class="p">({})</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="p">},</span>
<span class="p">}</span>
</code></pre></div>
<h3>Images</h3>
<p>When publishing images online, you can optimize them (using <code>optipng</code> and such
tools), without loss of quality (deleting metadata etc).</p>
<p>Ideally, you should run such programs on all your image files, but that is
painful to do. You can use the
<a href="https://github.com/tcoopman/image-webpack-loader"><code>image-webpack-loader</code></a>
instead to automatically run <code>optipng</code> (<span class="caps">PNG</span>), <code>pngquant</code> (<span class="caps">PNG</span>), <code>mozjpeg</code>
(<span class="caps">JPEG</span>), <code>svgo</code> (<span class="caps">SVG</span>) and <code>gifsicle</code> (<span class="caps">GIF</span>) on your image files, during build.
Here is a sample configuration for loading image files with this loader:</p>
<div class="highlight"><pre><span></span><code><span class="n">module</span><span class="o">.</span><span class="n">exports</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="err">…</span><span class="p">,</span>
<span class="w"> </span><span class="n">module</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">rules</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Regular</span><span class="w"> </span><span class="n">images</span>
<span class="w"> </span><span class="n">test</span><span class="p">:</span><span class="w"> </span><span class="o">/</span>\<span class="o">.</span><span class="p">(</span><span class="n">jpe</span><span class="err">?</span><span class="n">g</span><span class="o">|</span><span class="n">png</span><span class="o">|</span><span class="n">gif</span><span class="p">)</span><span class="o">$/</span><span class="p">,</span>
<span class="w"> </span><span class="n">use</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Once</span><span class="w"> </span><span class="n">processed</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="n">image</span><span class="o">-</span><span class="n">webpack</span><span class="o">-</span><span class="n">loader</span><span class="p">,</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">images</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">will</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">loaded</span><span class="w"> </span><span class="n">with</span><span class="w"> </span><span class="err">`</span><span class="n">url</span><span class="o">-</span><span class="n">loader</span><span class="err">`</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="n">eventually</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">inlined</span><span class="o">.</span>
<span class="w"> </span><span class="n">loader</span><span class="p">:</span><span class="w"> </span><span class="s1">'url-loader'</span><span class="p">,</span>
<span class="w"> </span><span class="n">options</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">name</span><span class="p">:</span><span class="w"> </span><span class="n">utils</span><span class="o">.</span><span class="n">assetsPath</span><span class="p">(</span><span class="s1">'images/[name].[hash:4].[ext]'</span><span class="p">),</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Images</span><span class="w"> </span><span class="n">larger</span><span class="w"> </span><span class="n">than</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="n">KB</span><span class="w"> </span><span class="n">won</span><span class="err">’</span><span class="n">t</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">inlined</span>
<span class="w"> </span><span class="n">limit</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">1024</span><span class="p">,</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">loader</span><span class="p">:</span><span class="w"> </span><span class="s1">'image-webpack-loader'</span><span class="p">,</span>
<span class="w"> </span><span class="n">options</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Only</span><span class="w"> </span><span class="n">use</span><span class="w"> </span><span class="n">image</span><span class="o">-</span><span class="n">webpack</span><span class="o">-</span><span class="n">loader</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">production</span><span class="p">,</span><span class="w"> </span><span class="n">no</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">need</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">slow</span><span class="w"> </span><span class="n">down</span><span class="w"> </span><span class="n">development</span><span class="w"> </span><span class="n">builds</span><span class="o">.</span>
<span class="w"> </span><span class="n">disable</span><span class="p">:</span><span class="w"> </span><span class="n">process</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">NODE_ENV</span><span class="w"> </span><span class="o">!==</span><span class="w"> </span><span class="s1">'production'</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">SVG</span><span class="w"> </span><span class="n">images</span><span class="p">,</span><span class="w"> </span><span class="n">same</span><span class="w"> </span><span class="n">logic</span><span class="w"> </span><span class="n">here</span>
<span class="w"> </span><span class="n">test</span><span class="p">:</span><span class="w"> </span><span class="o">/</span>\<span class="o">.</span><span class="n">svg</span><span class="o">$/</span><span class="p">,</span>
<span class="w"> </span><span class="n">use</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">loader</span><span class="p">:</span><span class="w"> </span><span class="s2">"svg-url-loader"</span><span class="p">,</span>
<span class="w"> </span><span class="n">options</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">name</span><span class="p">:</span><span class="w"> </span><span class="n">utils</span><span class="o">.</span><span class="n">assetsPath</span><span class="p">(</span><span class="s1">'images/[name].[hash:4].[ext]'</span><span class="p">),</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Images</span><span class="w"> </span><span class="n">larger</span><span class="w"> </span><span class="n">than</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="n">KB</span><span class="w"> </span><span class="n">won</span><span class="err">’</span><span class="n">t</span><span class="w"> </span><span class="n">be</span><span class="w"> </span><span class="n">inlined</span>
<span class="w"> </span><span class="n">limit</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">1024</span><span class="p">,</span>
<span class="w"> </span><span class="n">noquotes</span><span class="p">:</span><span class="w"> </span><span class="bp">true</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">loader</span><span class="p">:</span><span class="w"> </span><span class="s1">'image-webpack-loader'</span><span class="p">,</span>
<span class="w"> </span><span class="n">options</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">disable</span><span class="p">:</span><span class="w"> </span><span class="n">process</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">NODE_ENV</span><span class="w"> </span><span class="o">!==</span><span class="w"> </span><span class="s1">'production'</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="p">},</span>
<span class="p">};</span>
</code></pre></div>
<h3><span class="caps">HTML</span> built with HtmlWebpackPlugin</h3>
<p>You probably already use
<a href="https://github.com/jantimon/html-webpack-plugin"><code>HtmlWebpackPlugin</code></a> to
build your <code>index.html</code> file and inject scripts automatically. You can pass it
minification options as well:</p>
<div class="highlight"><pre><span></span><code><span class="n">module</span><span class="o">.</span><span class="n">exports</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="err">…</span><span class="p">,</span>
<span class="w"> </span><span class="n">plugins</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="n">new</span><span class="w"> </span><span class="n">HtmlWebpackPlugin</span><span class="p">({</span>
<span class="w"> </span><span class="n">filename</span><span class="p">:</span><span class="w"> </span><span class="s1">'index.html'</span><span class="p">,</span>
<span class="w"> </span><span class="n">template</span><span class="p">:</span><span class="w"> </span><span class="s1">'index.html'</span><span class="p">,</span>
<span class="w"> </span><span class="n">inject</span><span class="p">:</span><span class="w"> </span><span class="bp">true</span><span class="p">,</span><span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Inject</span><span class="w"> </span><span class="n">scripts</span>
<span class="w"> </span><span class="n">minify</span><span class="p">:</span><span class="w"> </span><span class="p">(</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Only</span><span class="w"> </span><span class="n">minify</span><span class="w"> </span><span class="ow">in</span><span class="w"> </span><span class="n">production</span>
<span class="w"> </span><span class="n">process</span><span class="o">.</span><span class="n">env</span><span class="o">.</span><span class="n">NODE_ENV</span><span class="w"> </span><span class="o">===</span><span class="w"> </span><span class="s1">'production'</span>
<span class="w"> </span><span class="err">?</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Options</span><span class="w"> </span><span class="n">are</span><span class="w"> </span><span class="n">coming</span><span class="w"> </span><span class="n">from</span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">kangax</span><span class="o">/</span><span class="n">html</span><span class="o">-</span><span class="n">minifier</span><span class="c1">#options-quick-reference.</span>
<span class="w"> </span><span class="n">collapseBooleanAttributes</span><span class="p">:</span><span class="w"> </span><span class="bp">true</span><span class="p">,</span>
<span class="w"> </span><span class="n">collapseWhitespace</span><span class="p">:</span><span class="w"> </span><span class="bp">true</span><span class="p">,</span>
<span class="w"> </span><span class="n">html5</span><span class="p">:</span><span class="w"> </span><span class="bp">true</span><span class="p">,</span>
<span class="w"> </span><span class="n">removeAttributeQuotes</span><span class="p">:</span><span class="w"> </span><span class="bp">true</span><span class="p">,</span>
<span class="w"> </span><span class="n">removeComments</span><span class="p">:</span><span class="w"> </span><span class="bp">true</span><span class="p">,</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="p">{}</span>
<span class="w"> </span><span class="p">),</span>
<span class="w"> </span><span class="p">}),</span>
<span class="w"> </span><span class="p">],</span>
<span class="p">};</span>
</code></pre></div>
<h2>Extract vendor libs in a separate chunk</h2>
<p>Vendor libs (all the code under <code>node_modules</code>) don’t change often, comparing
to your base code. Then, you can extract all the vendors libs code into a
dedicated chunk (another <span class="caps">JS</span> file). Whenever you update and rebuild your code,
if you did not update any of the <span class="caps">JS</span> dependencies of your app, the vendor code
will not change. Then, users will likely be able to use a cached version of
this chunk and only download the chunk containing your base code, which was
updated, resulting in smaller transfers.</p>
<p>This is easily doable in webpack using</p>
<div class="highlight"><pre><span></span><code><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="err">…</span><span class="p">,</span>
<span class="w"> </span><span class="nx">optimization</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="err">…</span><span class="p">,</span>
<span class="w"> </span><span class="nx">splitChunks</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Required for webpack to respect the vendor chunk. See</span>
<span class="w"> </span><span class="c1">// https://medium.com/dailyjs/webpack-4-splitchunks-plugin-d9fbbe091fd0</span>
<span class="w"> </span><span class="c1">// for more details.</span>
<span class="w"> </span><span class="nx">chunks</span><span class="o">:</span><span class="w"> </span><span class="s1">'initial'</span><span class="p">,</span>
<span class="w"> </span><span class="nx">cacheGroups</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">vendors</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Put everything from node_modules in this chunk</span>
<span class="w"> </span><span class="nx">test</span><span class="o">:</span><span class="w"> </span><span class="sr">/[\\/]node_modules[\\/]/</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="p">};</span>
</code></pre></div>
<h2>Split app in chunks, lazy loading routes</h2>
<p>Next step was to reduce as much as possible the size of the initial script,
that is the one required before any rendering could occur. Everything else
would be lazy loaded after the initial render. This way, the webapp appears to
be loading very fast, way before the user quits, tired of waiting (
<a href="https://developer.akamai.com/blog/2016/09/14/mobile-load-time-user-abandonment">half of your users</a>
will leave if the loading time is more than 3 seconds).</p>
<p>Typically, for Cycl’Assist, the <a href="https://cyclo.phyks.me/#/">onboarding view</a>
is systematically displayed at startup. This is actually a requirement as I am
using <a href="https://github.com/richtr/NoSleep.js">NoSleep</a> to prevent the device
from going to sleep in the map view (by playing a fake media file and media
files cannot be played without a prior user interaction in modern browsers).
Then, the map view is loaded when the user clicks the button to access it.</p>
<p>The map view requires heavy external libraries
(<a href="http://leafletjs.com/">Leaflet</a> or <a href="http://openlayers.org/">OpenLayers</a> to
display the map for instance) and weights 115 kB after Gzip. If it goes into a
dedicated chunk, this means the initial loading of the webapp will be much
lighter (about twice lighter actually)!</p>
<p>Lazy loading Vue routes can be easily achieved with Webpack dynamic import.</p>
<h3>Basic solution: just lazy load the components when required</h3>
<p>The most basic solution is simply to lazy load the chunk with the extra
components when entering the route. In your router definition, just use
something like this</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span><span class="w"> </span><span class="nx">Vue</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">'vue'</span><span class="p">;</span>
<span class="k">import</span><span class="w"> </span><span class="nx">Router</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">'vue-router'</span><span class="p">;</span>
<span class="nx">Vue</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">Router</span><span class="p">);</span>
<span class="kd">const</span><span class="w"> </span><span class="nx">LazyMap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="k">import</span><span class="p">(</span><span class="s1">'Map.vue'</span><span class="p">);</span><span class="w"> </span><span class="c1">// Dynamic import</span>
<span class="k">export</span><span class="w"> </span><span class="k">default</span><span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">Router</span><span class="p">({</span>
<span class="w"> </span><span class="nx">routes</span><span class="o">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">path</span><span class="o">:</span><span class="w"> </span><span class="s1">'/map'</span><span class="p">,</span>
<span class="w"> </span><span class="nx">name</span><span class="o">:</span><span class="w"> </span><span class="s1">'Map'</span><span class="p">,</span>
<span class="w"> </span><span class="nx">component</span><span class="o">:</span><span class="w"> </span><span class="nx">LazyMap</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">],</span>
<span class="p">});</span>
</code></pre></div>
<p>This is fine, but the chunk will only be downloaded when the user enters the
route. This means that there won’t be any feedback to the user when they enter
the route and while the chunk is downloaded, which might be misleading.</p>
<h3>More elaborate solution: lazy load the components when required but display feedback while loading</h3>
<p>A slightly more elaborate solution is to use Vue’s ability to handle lazy
loading to display feedback to the user (such as a progress bar).</p>
<div class="highlight"><pre><span></span><code><span class="o"><</span><span class="nx">template</span><span class="o">></span>
<span class="w"> </span><span class="o"><</span><span class="nb">Map</span><span class="o">><</span><span class="err">/Map></span>
<span class="o"><</span><span class="err">/template></span>
<span class="o"><</span><span class="nx">script</span><span class="o">></span>
<span class="c1">// Your Loading component, typically a spinner</span>
<span class="k">import</span><span class="w"> </span><span class="nx">Loading</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">'Loading.vue'</span><span class="p">;</span>
<span class="k">export</span><span class="w"> </span><span class="k">default</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">components</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">// Define a lazy-loaded component</span>
<span class="w"> </span><span class="nb">Map</span><span class="o">:</span><span class="w"> </span><span class="p">()</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">({</span>
<span class="w"> </span><span class="c1">// This is actually Vue magic. `component` is the dynamically</span>
<span class="w"> </span><span class="c1">// imported component, `loading` is a component to display during</span>
<span class="w"> </span><span class="c1">// loading.</span>
<span class="w"> </span><span class="nx">component</span><span class="o">:</span><span class="w"> </span><span class="k">import</span><span class="p">(</span><span class="s1">'Map.vue'</span><span class="p">),</span>
<span class="w"> </span><span class="nx">loading</span><span class="o">:</span><span class="w"> </span><span class="nx">Loading</span><span class="p">,</span>
<span class="w"> </span><span class="p">}),</span>
<span class="w"> </span><span class="p">},</span>
<span class="p">};</span>
<span class="o"><</span><span class="err">/script></span>
</code></pre></div>
<h3>Going further with chunk names: grouping dynamic imports</h3>
<p>Now we have a route which is lazy loaded and the size of the initial script
has reduced drastically, that’s fine. Still, there is an issue left: how to
group together imports of different components in a single chunk?</p>
<p>Typically, in Cycl’Assist, the map view is <a href="https://framagit.org/phyks/cyclassist/blob/012c6fd1be9cedd65f35f9568b34d75a5a0a51cd/src/views/LazyMap.vue">lazy
loaded</a>
and all the files to render this view are in a dedicated chunk. However, I had
to define related functions in other components. This is typically the case
for the “Export <span class="caps">GPX</span>” (export the current <span class="caps">GPS</span> trace), which has to be defined
<a href="https://framagit.org/phyks/cyclassist/blob/012c6fd1be9cedd65f35f9568b34d75a5a0a51cd/src/App.vue#L102-107">in the
menu</a>
but does not make sense to display before the user has seen the map and
started tracking their position. There is no need to load this part in the
initial chunk, it should go together with the map view in its dedicated chunk.</p>
<p>If we use the previous strategy to dynamically load the “Export <span class="caps">GPX</span>” code,
Webpack would put it in a third chunk, which does not make any sense. I’d
like this code to go together with the map view chunk. How to handle it?</p>
<p>The easy solution is to use named chunk. Actually, Webpack lets you specify a
name for the chunk created by a dynamic import, through a <span class="caps">JS</span> comment. To use
it, simply replace the previous <code>import('Map.vue)</code> by
<code>import('Map.vue' /* webpackChunkName: "MapView" */)</code>. This will name the
chunk “MapView” (you can put whatever you want, this is simply a name).</p>
<p>Then, when lazy loading the methods to export to <span class="caps">GPX</span>, you can specify the same
chunk name to put the code in the same chunk as the map view. For instance,</p>
<div class="highlight"><pre><span></span><code><span class="k">export</span><span class="w"> </span><span class="k">default</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">methods</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">exportGPX</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">import</span><span class="p">(</span><span class="s1">'exportGPX'</span><span class="w"> </span><span class="cm">/* webpackChunkName: "MapView" */</span><span class="p">).</span><span class="nx">then</span><span class="p">((</span><span class="nx">module</span><span class="p">)</span><span class="w"> </span><span class="p">=></span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">module</span><span class="p">.</span><span class="k">default</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">data</span><span class="p">);</span>
<span class="w"> </span><span class="p">});</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="p">};</span>
</code></pre></div>
<p>With this setup, the lazy loaded chunk are loaded whenever they are required
(typically when you browse to the corresponding view for instance). You can
also prefetch them, to start loading them as soon as the initial render is
done. More instructions on this are available at
<a href="https://mamot.fr/@glacasa/100708173580273735">https://mamot.fr/@glacasa/100708173580273735</a>
but I could not yet look into it, so this is untested.</p>
<h2>Only load the necessary bits from the libs you use</h2>
<h3>Use Babel 7, which comes with smarter polyfilling</h3>
<p>Babel 7 was <a href="https://babeljs.io/blog/2018/08/27/7.0.0">recently released</a> and
comes with a new (still experimental though)
<a href="https://babeljs.io/blog/2018/08/27/7.0.0#automatic-polyfilling-experimental">feature</a>
to help you reduce the size of your polyfills. You should really try using it!</p>
<p>With a basic configuration of prior versions of Babel, you are likely to have
a <code>.babelrc</code> file containing something similar to</p>
<div class="highlight"><pre><span></span><code>{
"presets": [
["env", { "modules": false }],
"stage-2"
]
}
</code></pre></div>
<p>This means you are using the <a href="https://babeljs.io/docs/en/babel-preset-env">“env”
preset</a>, which will enable syntax
transforms and polyfills based on your
<a href="https://github.com/browserslist/browserslist">browserlist</a> definitions. We
do not transform <span class="caps">ES6</span> modules (<code>"modules": false</code>) because we are using Webpack
as the build system. We also use the
<a href="https://babeljs.io/docs/en/babel-preset-stage-2">“stage-2”</a> transforms.</p>
<p>When you use Babel like this, you have to include a <code>import "@babel/polyfill"</code>
directive somewhere in your code (only once) to include the matching polyfills
for the features you enabled.</p>
<p>In Babel versions prior to 7, you could use <code>"useBuiltIns": "entry"</code> as an
option to the <code>env</code> preset to replace the global import of <code>@babel/polyfill</code>
(pulling the whole lib into your compiled files) by individual calls to the
specific polyfilled features in your preset (pulling only the polyfills
required for your browser targets). This was coming with a huge reduction of
the compiled files size, depending on your browsers target.</p>
<p>Still, this meant you would pull polyfills for all the features which were not
supported by your browsers target, even if you were not using them. Babel 7
introduced a new value for this option, <code>"useBuiltIns": "usage"</code>, which will
replace the global import of <code>@babel/polyfill</code> by individual imports for each
polyfilled feature <strong>you are using in your code</strong>, still based on your
browser targets. This feature is still experimental, but so far it works well
for my use case. There might be some false positives, meaning you are pulling
polyfills in your code base which you are not using, but this is not a big deal.</p>
<p>With two chunks involving loading parts of <code>@babel/polyfill</code>, the size went
down from 21.94 + 5.66 kB to 5.87 + 8.42 kB. That is a total reduction of
about 13 kB!</p>
<p>Note that the <code>.babelrc</code> and presets have slightly changed in Babel 7, but
there is <a href="https://babeljs.io/docs/en/next/v7-migration#stage-preset-deprecations-https-githubcom-babel-babel-issues-7770">an upgrade
tool</a>
which makes a great job. A similar configuration as the one at the beginning
of this section for Babel 7 is:</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="s2">"presets"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="s2">"@babel/preset-env"</span><span class="p">,</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s2">"modules"</span><span class="p">:</span><span class="w"> </span><span class="bp">false</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"useBuiltIns"</span><span class="p">:</span><span class="w"> </span><span class="s2">"usage"</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">]</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="s2">"plugins"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="s2">"@babel/plugin-syntax-dynamic-import"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"@babel/plugin-syntax-import-meta"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"@babel/plugin-proposal-class-properties"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"@babel/plugin-proposal-json-strings"</span><span class="p">,</span>
<span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="s2">"@babel/plugin-proposal-decorators"</span><span class="p">,</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="s2">"legacy"</span><span class="p">:</span><span class="w"> </span><span class="bp">true</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="s2">"@babel/plugin-proposal-function-sent"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"@babel/plugin-proposal-export-namespace-from"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"@babel/plugin-proposal-numeric-separator"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"@babel/plugin-proposal-throw-expressions"</span>
<span class="w"> </span><span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
<h3>Vuetify components</h3>
<p>My webapp is built around Vue and Vuetify. Vuetify is very nice to quickly
prototype an app as it includes tons of Material design components which play
nice together. It is really easy to use to quickly draw a basic interface out
of them. However, there is an obvious downside: Vuetify includes tons of
components (just have a look at <a href="https://vuetifyjs.com/en/components/api-explorer">the list of
components</a>), which makes it
heavy (about 25 kB of gzipped <span class="caps">CSS</span> and 117 kB of gzipped <span class="caps">JS</span>).</p>
<p>Luckily, Vuetify developpers thought about this and each component is defined
in its own file. Then, it is possible to only <a href="https://vuetifyjs.com/en/guides/a-la-carte">import the components you
need</a>, then reducing drastically
the size of the built files.</p>
<p>To only import the components you need from Vuetify, simply import it like this</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span><span class="w"> </span><span class="nx">Vue</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">'vue'</span><span class="p">;</span>
<span class="c1">// Import the core Vuetify code</span>
<span class="k">import</span><span class="w"> </span><span class="nx">Vuetify</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">'vuetify/es5/components/Vuetify'</span><span class="p">;</span>
<span class="c1">// First, import the base styles</span>
<span class="k">import</span><span class="w"> </span><span class="s1">'vuetify/src/stylus/app.styl'</span><span class="p">;</span>
<span class="c1">// Import required Vuetify components</span>
<span class="k">import</span><span class="w"> </span><span class="nx">VApp</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">'vuetify/es5/components/VApp'</span><span class="p">;</span><span class="w"> </span><span class="c1">// VApp is a core component, mandatory</span>
<span class="k">import</span><span class="w"> </span><span class="nx">VMenu</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">'vuetify/es5/components/VMenu'</span><span class="p">;</span><span class="w"> </span><span class="c1">// To import the v-menu component, for example</span>
<span class="nx">Vue</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">Vuetify</span><span class="p">,</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">components</span><span class="o">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nx">VApp</span><span class="p">,</span>
<span class="w"> </span><span class="nx">VMenu</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span>
<span class="p">});</span>
</code></pre></div>
<p>There is an <a href="https://vuetifyjs.com/en/guides/a-la-carte#ui-component-name-list">helper
tool</a> in
Vuetify doc to generate the imports you need based on the components you want
to import.</p>
<p>If you are converting an already existing code base, you first have to list
the Vuetify components you are using. I used this bash magic one liner (which
might have issues, use at your own risks) which you can run in the folder
containing all your source <span class="caps">JS</span> and Vue files:</p>
<div class="highlight"><pre><span></span><code>ack<span class="w"> </span><span class="s1">'<v-'</span><span class="w"> </span>.<span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span>-e<span class="w"> </span><span class="s1">'s/^src\\/.*:[[:space:]]*<//'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s1">'^v-'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sed<span class="w"> </span>-e<span class="w"> </span><span class="s1">'s/\\(v-[^[:space:]>]*\\).*/\\1/'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sort<span class="w"> </span><span class="p">|</span><span class="w"> </span>uniq
</code></pre></div>
<p>Importing only the components I use in Vuetify, Vuetify only contributes for
39 kB of <span class="caps">JS</span> after gzip to my vendors chunk.</p>
<h3>Moment locales</h3>
<p>If you are using <a href="https://momentjs.com/">Moment.<span class="caps">JS</span></a> to handle your dates in
<span class="caps">JS</span>, first you should be aware that the default build requires all the locales
from Moment, even if you don’t use them. You should <a href="https://github.com/jmblog/how-to-optimize-momentjs-with-webpack">only load the locales you
need</a>, which
can be easily done in Webpack using the following plugin</p>
<div class="highlight"><pre><span></span><code><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">...,</span>
<span class="w"> </span><span class="nx">plugins</span><span class="o">:</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="c1">// Don't include any Moment locale</span>
<span class="w"> </span><span class="ow">new</span><span class="w"> </span><span class="nx">webpack</span><span class="p">.</span><span class="nx">IgnorePlugin</span><span class="p">(</span><span class="sr">/^\.\/locale$/</span><span class="p">,</span><span class="w"> </span><span class="sr">/moment$/</span><span class="p">),</span>
<span class="w"> </span><span class="p">],</span>
<span class="p">};</span>
</code></pre></div>
<p>and in your own code you can then manually require explicitly the locales you need</p>
<div class="highlight"><pre><span></span><code><span class="k">import</span><span class="w"> </span><span class="nx">moment</span><span class="w"> </span><span class="kr">from</span><span class="w"> </span><span class="s1">'moment'</span><span class="p">;</span>
<span class="k">import</span><span class="w"> </span><span class="s1">'moment/locale/en'</span><span class="p">;</span>
<span class="k">import</span><span class="w"> </span><span class="s1">'moment/locale/fr'</span><span class="p">;</span>
<span class="nx">moment</span><span class="p">.</span><span class="nx">locale</span><span class="p">(</span><span class="s1">'fr'</span><span class="p">);</span><span class="w"> </span><span class="c1">// Set default Moment locale</span>
</code></pre></div>
<p>Dropping the unused locales, you spare a few kB per locale (and there are tons
of them!) :)</p>
<h2>Drop useless libs or find lighter alternatives</h2>
<h3>Replace Moment by date-fns or custom script</h3>
<p>Moment is not very modular and the whole library will be added, no
matter whether you use all the features or only a handful of them. With French
and English locales only, this results in 17 kB after gzip for Cycl’Assist.</p>
<p>Another option is to move to <code>date-fns</code> which is a collection of useful
functions to work with dates (think lodash), rather than the global object
approach from Moment. This is much more modular and you can only import the
specific features you need. For Cycl’Assist, this is basically <a href="https://date-fns.org/v1.29.0/docs/distanceInWordsToNow">relative
times</a>,
<a href="https://date-fns.org/v1.29.0/docs/format">formatting</a> and
<a href="https://date-fns.org/v1.29.0/docs/parse">parsing</a> <span class="caps">ISO</span> 8601 strings. For
Cycl’Assist, this means going down from 17 kB after gzip (using Moment) to a
handful of kB (using <code>date-fns</code>), which is a huge improve.</p>
<p>However, these libraries might be super useful when you prototype something,
as they will provide you with tons of functions at hand, but once your webapp
is stabilized, you can check and you probably use only a very small portion of
the possibilities of such libraries. Sadly, JavaScript does not have advanced
functions built-in for formatting and computing relative dates, but there is a
<a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Date/parse"><code>Date.parse()</code></a>
function to parse <span class="caps">ISO</span> 8601 strings (beware that it returns a milliseconds
timestamp, not a <code>Date</code> object!) and to do <a href="https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Date/toLocaleString">all-in-one
formatting</a>
according to locale.</p>
<p>Doing basic formatting of dates in <span class="caps">JS</span> and computing relative times can be done
in <a href="https://gist.github.com/Phyks/ece72f9e5667ecbd02788bba3d41157b">less than 100
lines</a> and
this, together with the built-ins functions, should be enough for most
projects (at least it is sufficient for Cycl’Assist). The resulting file size
after minification and gzip is 600 bytes. That’s 28 times lighter than
optimized Moment!</p>
<h3><code>gps-to-gpx</code> and <code>xmlbuilder</code></h3>
<p>To build the <span class="caps">GPX</span> file from the <span class="caps">GPS</span> points, I am relying on a nice
<a href="https://github.com/pdhoopr/gps-to-gpx/">library</a>. Sadly, the library was
written with Node in mind, and not the browser. As Node does not have any
built-in to generate and manipulate <span class="caps">XML</span> trees, it was relying on
<a href="https://www.npmjs.com/package/xmlbuilder">xmlbuilder</a>.</p>
<p>I’m using this library in a browser context and browsers have <a href="https://caniuse.com/#feat=xml-serializer"><span class="caps">DOM</span> parsing and
serialization</a> APIs which can be
used to manipulate and generate <span class="caps">XML</span>.</p>
<p>Rewriting the <span class="caps">XML</span> generation part of the <code>gps-to-gpx</code> library to use the
browser APIs means that we can get rid of <code>xmlbuilder</code> in the compiled files.
This is 7.8kB less ! Note that the same code could potentially be used with a
Node backend, using <a href="https://github.com/jindw/xmldom">xmldom</a> to polyfill the
required APIs.</p>
<h3>Howler to play sounds</h3>
<p>In Cycl’Assist, I wanted to play a sound whenever the user approaches a known
report. For quick and easy prototyping, I was using
<a href="https://github.com/goldfire/howler.js">Howler</a> which has the great benefit of
taking care of everything for you and ensuring compatibility with as many
browsers as possible. Of course, it comes with the downside that it makes for
7 kB of gzipped <span class="caps">JS</span>.</p>
<p>For my particular use case, the <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement">Audio
<span class="caps">API</span></a> was
more than enough. I did not need support for playlists nor <a href="https://github.com/goldfire/howler.js#mobile-playback">advanced tricks for
autoplay on mobile devices</a>.
Audio element is <a href="https://caniuse.com/#feat=audio">well supported</a> and so is
<a href="https://caniuse.com/#feat=mp3"><span class="caps">MP3</span> format</a>.</p>
<h2>Other ideas</h2>
<p>Here are some other ideas, which are not really useful for Cycl’Assist at the
moment but might be for you:</p>
<ul>
<li>If you have a lot of translations and they represent enough kB to worry
about, you could <a href="https://kazupon.github.io/vue-i18n/guide/lazy-loading.html">lazy load
them</a>.</li>
<li>There are some <a href="https://philipwalton.com/articles/loading-polyfills-only-when-needed/">nice
ideas</a>
to load polyfills in a dedicated chunk only on browsers which need them
(and without relying on <a href="https://polyfill.io/v2/docs/">polyfills.io</a>).
Sadly, this is <a href="https://github.com/babel/babel/issues/6635#issue-269652538">not
implemented</a>
or easily doable with Babel <code>useBuiltIns: usage</code> feature :(</li>
</ul>
<h2>Conclusion</h2>
<p>Initially, I had two chunks: a “vendor” chunk (everything from <code>node_modules</code>)
which was around 190 kB (after gzip) and an app chunk which was around 25 kB
(after gzip). Both had to be loaded before the app could start to render,
meaning an initial payload of about 215 kB (after gzip). The production build
time was 70 s (but this already included <code>image-webpack-loader</code> processing for instance).</p>
<p>After going through the steps described in this guide, corresponding to <a href="https://framagit.org/phyks/cyclassist/commit/1139dc33c5a22e949db67f16ca5813e95d9e1018">this
commit</a>,
I now have three chunks:
* A “vendor” chunk, which is about 90 kB (after gzip).
* An initial “app” chunk, which is about 27 kB (after gzip).
* A lazy-loaded chunk for the map view, which is about 90 kB (after gzip).</p>
<p>The total size of the <span class="caps">JS</span> files did not change much. It actually slightly
increased, but this is not a fair comparison as I added new features and moved
from Leaflet to OpenLayers, which is about three times heavier. The important
part is that my initial payload (required for the first render) was 215 kB
whereas now I have an initial payload of 90 + 27 = 117 kB. This is 100 kB less
or equivalently <strong>2 seconds less</strong> when browsing using a mobile phone relying on a
<a href="https://fr.wikipedia.org/wiki/3G">perfect <span class="caps">EDGE</span> / typical urban 3G connection</a>
(link in French).</p>
<p>The final production build time is about 50s.</p>
<p>Note that I am still working on optimizing this webapp for mobile connections.
I will keep this article updated as I find new ways to reduce the compiled
webapp size.</p>Utiliser sa caméra embarquée de vélo pour envoyer des photos sur Mapillary2018-08-22T16:00:00+02:002018-08-22T16:00:00+02:00Phykstag:localhost,2018-08-22:/Blog/output/2018/08/utiliser-sa-camera-embarquee-de-velo-pour-envoyer-des-photos-sur-mapillary.html<p><a href="http://mapillary.com/">Mapillary</a> est un service permettant de prendre et
partager des photos prises directement au niveau de la rue. Les photos
partagées sont traitées par Mapillary (qui vend des traitements de photos
prises dans la rue pour notamment en extraire de l’information) et disponibles
pour tous sous une licence Creative Commons. Les photos (et une partie des
résultats de traitement, dont les panneaux par exemple) sont également
utilisables directement pour éditer
<a href="http://openstreetmap.org/">OpenStreetMap</a>. Plus d’informations sur le service
sont disponibles dans <a href="https://linuxfr.org/news/cartographie-et-images-de-rues-mapillary-et-openstreetcam">cet article de
linuxfr</a>.</p>
<p>Quitte à avoir une caméra embarquée sur son vélo, pourquoi ne pas s’en servir
pour contribuer des images à ce service ?</p>
<p><a href="http://mapillary.com/">Mapillary</a> est un service permettant de prendre et
partager des photos prises directement au niveau de la rue. Les photos
partagées sont traitées par Mapillary (qui vend des traitements de photos
prises dans la rue pour notamment en extraire de l’information) et disponibles
pour tous sous une licence Creative Commons. Les photos (et une partie des
résultats de traitement, dont les panneaux par exemple) sont également
utilisables directement pour éditer
<a href="http://openstreetmap.org/">OpenStreetMap</a>. Plus d’informations sur le service
sont disponibles dans <a href="https://linuxfr.org/news/cartographie-et-images-de-rues-mapillary-et-openstreetcam">cet article de
linuxfr</a>.</p>
<p>Quitte à avoir une caméra embarquée sur son vélo, pourquoi ne pas s’en servir
pour contribuer des images à ce service ?</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/08/camera_embarquee_velo_mapillary/IMG_20180822_113559.jpg">
<img style="max-width: 40%; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/08/camera_embarquee_velo_mapillary/IMG_20180822_113559.jpg" alt="Montage de ma caméra sur mon vélo, vue de face" />
</a>
<a href="http://localhost/Blog/output/images/2018/08/camera_embarquee_velo_mapillary/IMG_20180822_113626.jpg">
<img style="max-width: 40%; margin-left: 1em; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/08/camera_embarquee_velo_mapillary/IMG_20180822_113626.jpg" alt="Montage de ma caméra sur mon vélo, vue de dos" />
</a>
</p>
<h2>Utilisation en caméra embarquée pour le vélo</h2>
<p>J’ai récemment décidé de monter une caméra embarquée sur mon vélo, pour filmer
la route devant moi. Mon montage est très basique et consiste en une Xiaomi Yi
Action 2K (d’un excellent rapport qualité/prix et suffisante pour cette
fonction, trouvée autour de 50€ avec son boîtier étanche à l’occasion d’une
promotion, il y en a très souvent sur le site
<a href="http://dealabs.com/">dealabs.com</a>). La caméra est régulièrement mise à jour
par le constructeur (pour l’instant), il y a <a href="https://github.com/PJanisio/Xiaomi_Yi_autoexec">une certaine communauté
autour</a>, ce qui est plutôt
encourageant pour l’instant. Il existe aussi un modèle 4K, beaucoup plus cher.</p>
<p>Pour la fixation sur guidon, j’utilise un adaptateur de <a href="https://i.ebayimg.com/images/g/q5oAAOSwwPtTvvil/s-l1600.jpg">ce
genre</a>, trouvé à
5€ sur Ebay, monté sur mon guidon avec un bout de chambre à air pour une
meilleure adhérence. Attention en achetant, il y a deux types de modèles, ceux
qui auront la caméra dans l’axe du guidon (pas très utile) et ceux qui auront
la caméra perpendiculaire avec le guidon (comme sur la photo) !</p>
<p>Finalement, pour une cinquantaine d’euros, on peut obtenir <a href="https://pub.phyks.me/videos/Aith6zoo.mp4">ce genre de
vidéos</a> (non retouchée, qualité
identique à celle fournie par la caméra), ce qui est suffisant dans la plupart
des cas (de jour) pour avoir une trace et un numéro de plaque. La caméra filme
en 2k à 30fps (vidéo ci-dessus) ou en Full <span class="caps">HD</span> à 60fps (mais j’ai l’impression
qu’une meilleure résolution est plus utile qu’un haut débit d’images). Avec la
batterie d’origine, je peux filmer environ 1h dans cette qualité ce qui est
suffisant pour moi. Sinon, des batteries de rechange se trouvent facilement
pour quelques euros en ligne.</p>
<p>Seul bémol, il faut une application (non-libre) pour mettre à jour le firmware
et modifier les réglages de la caméra.</p>
<p><em>Note</em> : Mapillary propose de prendre des photos directement avec votre
téléphone, monté sur votre vélo, et vous fournit même un <a href="https://shop.mapillary.com/">support
gratuitement</a>. Le support envoyé est de très
mauvaise qualité, et il y a de grandes chances que votre téléphone s’explose
par terre au premier dos d’âne (heureusement, le Fairphone 1 est résistant, il
n’a rien eu !). Utiliser un autre support pour filmer est éventuellement
envisageable, mais l’orienter correctement pour filmer impose quasiment de ne
pas pouvoir s’en servir en guidage :/</p>
<h2>Prendre des photos pour Mapillary</h2>
<p>Le cas d’usage le plus simple (et le meilleur en termes de qualité de prise de
vue !) est lorsque vous n’utilisez pas votre caméra pour filmer. Typiquement,
lorsque vous faites du cyclotourisme sur voie verte, il y a peu de chances que
vous ayiez besoin d’avoir votre caméra embarquée allumée. Dans ce cas, le plus
simple est de passer la caméra en mode “timelapse” en prenant une photo toutes
les quelques secondes (2 ou 5 secondes par exemple).</p>
<p>En parallèle, au moment de démarrer l’enregistrement, commencez
l’enregistrement d’une trace <span class="caps">GPX</span> sur votre téléphone. Cela peut se faire
facilement sur votre téléphone sur Android avec
<a href="http://osmand.net/features?id=trip-recording-plugin">OsmAnd~</a> (disponible
sur <a href="http://f-droid.org/">F-Droid</a>). Choisissez une fréquence d’enregistrement
au moins égale à la fréquence de capture des images idéalement.</p>
<p>Prenez également une photo de l’horloge de votre téléphone avec votre caméra à
un moment du trajet, pour pouvoir faire facilement correspondre l’heure de
votre caméra à l’heure de votre téléphone pour associer des points <span class="caps">GPS</span> aux images.</p>
<p>En rentrant de balade, il faut récupérer les photos, leur associer des points
<span class="caps">GPS</span> et les envoyer chez Mapillary. Ils fournissent pour cela un ensemble de
<a href="https://github.com/mapillary/mapillary_tools">scripts Python</a> fort pratique.
Voici le script (à lancer dans un dossier contenant toutes vos photos et votre
tace <span class="caps">GPX</span>) que j’utilise pour gérer tout ça :</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="nb">set</span><span class="w"> </span>-e
<span class="c1"># Upload a set of images from dashcam Xiaomi Yi.</span>
<span class="c1"># Usage: ./xiaomi_photos.sh OFFSET_TIME</span>
<span class="c1"># where OFFSET_TIME is the camera time - GPS time (in seconds).</span>
<span class="nv">OFFSET_TIME</span><span class="o">=</span><span class="nv">$1</span><span class="w"> </span><span class="c1"># This is camera time - GPS time</span>
<span class="nv">PHOTOS_FILES</span><span class="o">=</span><span class="k">$(</span>ls<span class="w"> </span>*.jpg<span class="k">)</span>
<span class="nv">GPX_PATH</span><span class="o">=</span><span class="k">$(</span>ls<span class="w"> </span>*.gpx<span class="k">)</span>
<span class="nv">DUPLICATE_DISTANCE</span><span class="o">=</span><span class="m">1</span>
<span class="nv">MAPILLARY_USER_NAME</span><span class="o">=</span><span class="s2">"YOUR MAPILLARY USER NAME"</span><span class="w"> </span><span class="c1"># To be edited</span>
<span class="nv">OUTPUT_PATH</span><span class="o">=</span><span class="s2">"out"</span>
<span class="c1"># Different steps</span>
<span class="nv">PROCESS</span><span class="o">=</span><span class="nb">true</span>
<span class="nv">UPLOAD</span><span class="o">=</span><span class="nb">true</span>
<span class="c1"># Ensure folders exist</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>!<span class="w"> </span>-d<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">OUTPUT_PATH</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>mkdir<span class="w"> </span><span class="si">${</span><span class="nv">OUTPUT_PATH</span><span class="si">}</span>
<span class="k">fi</span>
<span class="c1"># Make a copy of photos, to prevent the mapillary scripts from editing the</span>
<span class="c1"># original files</span>
cp<span class="w"> </span><span class="si">${</span><span class="nv">PHOTOS_FILES</span><span class="si">}</span><span class="w"> </span><span class="si">${</span><span class="nv">OUTPUT_PATH</span><span class="si">}</span>/
<span class="c1"># Match photos with GPS coordinates</span>
<span class="c1"># Photos too close will be considered as duplicates and not sent.</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$PROCESS</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">true</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>mapillary_tools<span class="w"> </span>--advanced<span class="w"> </span>process<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--import_path<span class="w"> </span><span class="si">${</span><span class="nv">OUTPUT_PATH</span><span class="si">}</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--geotag_source<span class="w"> </span>gpx<span class="w"> </span>--geotag_source_path<span class="w"> </span><span class="si">${</span><span class="nv">GPX_PATH</span><span class="si">}</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--device_make<span class="w"> </span>Xiaomi<span class="w"> </span>--device_model<span class="w"> </span><span class="s2">"Yi Action 2K"</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--interpolate_directions<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--flag_duplicates<span class="w"> </span>--duplicate_distance<span class="w"> </span><span class="si">${</span><span class="nv">DUPLICATE_DISTANCE</span><span class="si">}</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--local_time<span class="w"> </span>--offset_time<span class="w"> </span><span class="si">${</span><span class="nv">OFFSET_TIME</span><span class="si">}</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--user_name<span class="w"> </span><span class="si">${</span><span class="nv">MAPILLARY_USER_NAME</span><span class="si">}</span>
<span class="k">fi</span>
<span class="c1"># At this point, feel free to edit your photos in the out/ folder. Typically,</span>
<span class="c1"># delete any privacy-concerning photo etc. Only the remaining photos will be</span>
<span class="c1"># uploaded in next step.</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$UPLOAD</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">true</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span><span class="c1"># Upload images</span>
<span class="w"> </span><span class="nb">read</span><span class="w"> </span>-p<span class="w"> </span><span class="s2">"Edit photos. Enter y when ready to upload. "</span><span class="w"> </span>-n<span class="w"> </span><span class="m">1</span><span class="w"> </span>-r
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="c1"># move to a new line</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="nv">$REPLY</span><span class="w"> </span><span class="o">=</span>~<span class="w"> </span>^<span class="o">[</span>Yy<span class="o">]</span>$<span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span><span class="c1"># Or alternatively, use the Mapillary uploader for easy visual</span>
<span class="w"> </span><span class="c1"># confirmation that everything went fine.</span>
<span class="w"> </span>mapillary_tools<span class="w"> </span>upload<span class="w"> </span>--import_path<span class="w"> </span><span class="si">${</span><span class="nv">OUTPUT_PATH</span><span class="si">}</span><span class="w"> </span>--manual_done
<span class="w"> </span><span class="k">fi</span>
<span class="k">fi</span>
<span class="c1"># Remove folders</span>
<span class="nb">read</span><span class="w"> </span>-p<span class="w"> </span><span class="s2">"Remove all temporary files. Enter y when ready to remove. "</span><span class="w"> </span>-n<span class="w"> </span><span class="m">1</span><span class="w"> </span>-r
<span class="nb">echo</span><span class="w"> </span><span class="c1"># move to a new line</span>
<span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="nv">$REPLY</span><span class="w"> </span><span class="o">=</span>~<span class="w"> </span>^<span class="o">[</span>Yy<span class="o">]</span>$<span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>rm<span class="w"> </span>-r<span class="w"> </span><span class="si">${</span><span class="nv">OUTPUT_PATH</span><span class="si">}</span>
<span class="w"> </span>rm<span class="w"> </span>-r<span class="w"> </span><span class="si">${</span><span class="nv">TMP_PATH</span><span class="si">}</span>
<span class="k">fi</span>
</code></pre></div>
<p>Un exemple de ce mode de fonctionnement et des photos résultantes est visible
<a href="https://www.mapillary.com/map/im/PIodkpaID-2O_BeLfrCxPg">ici</a>.</p>
<h2>Extraire des photos pour Mapillary d’une vidéo en mode caméra embarquée</h2>
<p>Malheureusement, souvent, vous voulez quand même avoir votre caméra embarquée
qui filme en permanence. C’est notamment le cas lorsque vous circulez en ville
à vélo, pour avoir des images -(de plaques d’immatriculation en particulier)
en cas d’éventuel accident et de délit de fuite. Dans ce cas, une autre
solution est possible en extrayant des photos depuis les vidéos capturées et
là encore, les outils Mapillary nous facilitent la tâche.</p>
<p>La limitation principale de ce mode est que votre vidéo est en général filmée
en 2K à 30 images par seconde, ce qui est de bien moins bonne qualité qu’en
mode “timelapse” (16M pixels, temps de pose court). Du coup, les photos
extraites sont forcément de moins bonne qualité et plus facilement floue.
Cependant, en ville, les résultats semblent plus qu’acceptables pour un
certain nombre de tâches d’édition (revêtement, limitations de vitesses,
confirmer la présence de tel ou tel commerce, confirmer un élément urbain, etc).</p>
<p>Dans mon cas, je filme toujours en mode “en boucle” quand je l’utilise comme
une caméra embarquée. La caméra génère donc des fichiers vidéos de 10 minutes
et les écrase au fur et à mesure, dès qu’elle manque de place. Voici le script
(à lancer dans un dossier contenant toutes vos vidéos, les
fichiers de miniatures contenant les informations <span class="caps">EXIF</span>, .<span class="caps">THM</span>, et votre tace
<span class="caps">GPX</span>) que j’utilise pour recoller toutes les vidéos et gérer l’extraction de
photos, l’association de coordonnées <span class="caps">GPS</span> et l’envoi à Mapillary :</p>
<div class="highlight"><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="nb">set</span><span class="w"> </span>-e
<span class="c1"># Upload a set of images from video from dashcam Xiaomi Yi.</span>
<span class="c1"># Usage: ./xiaomi_videos.sh VIDEO_START_TIME</span>
<span class="c1"># where VIDEO_START_TIME is the starting time (as a timestamp, in</span>
<span class="c1"># milliseconds) of the video file.</span>
<span class="nv">VIDEO_FILES</span><span class="o">=</span><span class="k">$(</span>ls<span class="w"> </span>*.mp4<span class="k">)</span>
<span class="nv">THM_FILES</span><span class="o">=</span><span class="k">$(</span>ls<span class="w"> </span>*.THM<span class="k">)</span>
<span class="nv">GPX_PATH</span><span class="o">=</span><span class="k">$(</span>ls<span class="w"> </span>*.gpx<span class="k">)</span>
<span class="nv">DUPLICATE_DISTANCE</span><span class="o">=</span><span class="m">1</span>
<span class="nv">MAPILLARY_USER_NAME</span><span class="o">=</span><span class="s2">"YOUR MAPILLARY USER NAME"</span>
<span class="nv">TMP_PATH</span><span class="o">=</span><span class="s2">"tmp"</span>
<span class="nv">OUTPUT_PATH</span><span class="o">=</span><span class="s2">"out"</span>
<span class="nv">CONCAT_VIDEO_FILE</span><span class="o">=</span><span class="s2">"tmp/out.mp4"</span>
<span class="nv">VIDEO_SAMPLE_INTERVAL</span><span class="o">=</span><span class="m">2</span>
<span class="c1"># Different steps</span>
<span class="nv">CONVERT</span><span class="o">=</span><span class="nb">true</span>
<span class="nv">SAMPLE</span><span class="o">=</span><span class="nb">true</span>
<span class="nv">PROCESS</span><span class="o">=</span><span class="nb">true</span>
<span class="nv">UPLOAD</span><span class="o">=</span><span class="nb">true</span>
<span class="c1"># Ensure folders exist</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>!<span class="w"> </span>-d<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">OUTPUT_PATH</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>mkdir<span class="w"> </span><span class="si">${</span><span class="nv">OUTPUT_PATH</span><span class="si">}</span>
<span class="k">fi</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>!<span class="w"> </span>-d<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">TMP_PATH</span><span class="si">}</span><span class="s2">"</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>mkdir<span class="w"> </span><span class="si">${</span><span class="nv">TMP_PATH</span><span class="si">}</span>
<span class="k">fi</span>
<span class="c1"># First, concatenate all video files into a single one in a temporary file as</span>
<span class="c1"># Mapillary tools can only process single video files.</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$CONVERT</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">true</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span><span class="c1"># Generate concatenation list of MP4 files</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-f<span class="w"> </span><span class="s2">"</span><span class="si">${</span><span class="nv">TMP_PATH</span><span class="si">}</span><span class="s2">/concat_list.txt"</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>rm<span class="w"> </span><span class="si">${</span><span class="nv">TMP_PATH</span><span class="si">}</span>/concat_list.txt
<span class="w"> </span><span class="k">fi</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span>f<span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="si">${</span><span class="nv">VIDEO_FILES</span><span class="si">}</span><span class="p">;</span><span class="w"> </span><span class="k">do</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"file '../</span><span class="k">$(</span>basename<span class="w"> </span><span class="nv">$f</span><span class="k">)</span><span class="s2">'"</span><span class="w"> </span>>><span class="w"> </span><span class="si">${</span><span class="nv">TMP_PATH</span><span class="si">}</span>/concat_list.txt
<span class="w"> </span><span class="k">done</span>
<span class="w"> </span><span class="c1"># Concatenate video files</span>
<span class="w"> </span>ffmpeg<span class="w"> </span>-f<span class="w"> </span>concat<span class="w"> </span>-safe<span class="w"> </span><span class="m">0</span><span class="w"> </span>-i<span class="w"> </span><span class="si">${</span><span class="nv">TMP_PATH</span><span class="si">}</span>/concat_list.txt<span class="w"> </span>-c<span class="w"> </span>copy<span class="w"> </span><span class="si">${</span><span class="nv">CONCAT_VIDEO_FILE</span><span class="si">}</span>
<span class="k">fi</span>
<span class="c1"># Then, extract images from the video at a given sample interval (2 seconds</span>
<span class="c1"># typically)</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$SAMPLE</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">true</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span><span class="c1"># Compute it from http://legacy.mapillary.com/map/upload/vi</span>
<span class="w"> </span><span class="nv">VIDEO_START_TIME</span><span class="o">=</span><span class="nv">$1</span>
<span class="w"> </span><span class="c1"># Extract images</span>
<span class="w"> </span>mapillary_tools<span class="w"> </span>--advanced<span class="w"> </span>sample_video<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--import_path<span class="w"> </span><span class="si">${</span><span class="nv">OUTPUT_PATH</span><span class="si">}</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--video_file<span class="w"> </span><span class="si">${</span><span class="nv">CONCAT_VIDEO_FILE</span><span class="si">}</span><span class="w"> </span>--video_sample_interval<span class="w"> </span><span class="si">${</span><span class="nv">VIDEO_SAMPLE_INTERVAL</span><span class="si">}</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--video_start_time<span class="w"> </span><span class="si">${</span><span class="nv">VIDEO_START_TIME</span><span class="si">}</span>
<span class="k">fi</span>
<span class="c1"># Then, match each image with a GPS coordinate from the GPX track</span>
<span class="c1"># Photos too close will be considered as duplicates and not sent.</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$PROCESS</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">true</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>mapillary_tools<span class="w"> </span>--advanced<span class="w"> </span>process<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--import_path<span class="w"> </span><span class="si">${</span><span class="nv">OUTPUT_PATH</span><span class="si">}</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--geotag_source<span class="w"> </span>gpx<span class="w"> </span>--geotag_source_path<span class="w"> </span><span class="si">${</span><span class="nv">GPX_PATH</span><span class="si">}</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--device_make<span class="w"> </span>Xiaomi<span class="w"> </span>--device_model<span class="w"> </span><span class="s2">"Yi Action 2K"</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--interpolate_directions<span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--flag_duplicates<span class="w"> </span>--duplicate_distance<span class="w"> </span><span class="si">${</span><span class="nv">DUPLICATE_DISTANCE</span><span class="si">}</span><span class="w"> </span><span class="se">\</span>
<span class="w"> </span>--user_name<span class="w"> </span><span class="si">${</span><span class="nv">MAPILLARY_USER_NAME</span><span class="si">}</span>
<span class="k">fi</span>
<span class="c1"># At this point, feel free to edit your photos in the out/ folder. Typically,</span>
<span class="c1"># delete any privacy-concerning photo etc. Only the remaining photos will be</span>
<span class="c1"># uploaded in next step.</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="s2">"</span><span class="nv">$UPLOAD</span><span class="s2">"</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">true</span><span class="w"> </span><span class="o">]</span><span class="w"> </span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span><span class="c1"># Upload images</span>
<span class="w"> </span><span class="nb">read</span><span class="w"> </span>-p<span class="w"> </span><span class="s2">"Edit videos. Enter y when ready to upload. "</span><span class="w"> </span>-n<span class="w"> </span><span class="m">1</span><span class="w"> </span>-r
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="c1"># move to a new line</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="nv">$REPLY</span><span class="w"> </span><span class="o">=</span>~<span class="w"> </span>^<span class="o">[</span>Yy<span class="o">]</span>$<span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>mapillary_tools<span class="w"> </span>upload<span class="w"> </span>--import_path<span class="w"> </span><span class="si">${</span><span class="nv">OUTPUT_PATH</span><span class="si">}</span><span class="w"> </span>--manual_done
<span class="w"> </span><span class="k">fi</span>
<span class="k">fi</span>
<span class="c1"># Remove folders</span>
<span class="nb">read</span><span class="w"> </span>-p<span class="w"> </span><span class="s2">"Remove all temporary files. Enter y when ready to remove. "</span><span class="w"> </span>-n<span class="w"> </span><span class="m">1</span><span class="w"> </span>-r
<span class="nb">echo</span><span class="w"> </span><span class="c1"># move to a new line</span>
<span class="k">if</span><span class="w"> </span><span class="o">[[</span><span class="w"> </span><span class="nv">$REPLY</span><span class="w"> </span><span class="o">=</span>~<span class="w"> </span>^<span class="o">[</span>Yy<span class="o">]</span>$<span class="w"> </span><span class="o">]]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>rm<span class="w"> </span>-r<span class="w"> </span><span class="si">${</span><span class="nv">OUTPUT_PATH</span><span class="si">}</span>
<span class="w"> </span>rm<span class="w"> </span>-r<span class="w"> </span><span class="si">${</span><span class="nv">TMP_PATH</span><span class="si">}</span>
<span class="k">fi</span>
</code></pre></div>
<p>Pour calculer l’heure de prise de vue, la solution la plus pratique que j’ai
trouvée pour l’instant est d’utiliser <a href="https://legacy.mapillary.com/map/upload/vi">le téléverseur de vidéos de
Mapillary</a>. Sélectionnez votre
fichier vidéo et votre trace <span class="caps">GPX</span>, cherchez une intersection facilement
reconnaissable et ajuster la position du point bleu sur la carte en suivant
les instructions. Revenez ensuite au début de la vidéo et notez la valeur de
“Video time” qu’il suffit ensuite de convertir en timestamp (en millisecondes)
pour le passer au script.</p>
<p>Une autre possibilité, si vous connaissez précisément le décalage entre
l’heure de votre caméra et celle de votre téléphone, est d’utiliser
<code>--offset-time</code> comme précédemment. Cependant, je n’ai pas eu de très bons
résultats sur des vidéos avec cette méthode, et l’utilisation de l’heure de
démarrage de la vidéo, calculée depuis le téléverseur, m’a donné de meilleurs résultats.</p>
<p><em>Note</em> : Vous pouvez aussi utiliser le téléverseur de Mapillary de bout en
bout, mais vos vidéos seront intégralement envoyées sur leurs serveurs, ce qui
me posait des problèmes de confidentialité (et il faudrait aller prédécouper
les vidéos pour ne conserver que les séquences non problématiques pour la vie privée).</p>
<p>Un exemple de ce mode de fonctionnement et des images résultantes est visible
<a href="https://www.mapillary.com/map/im/2pYsYIRzakfu-TIMDTwyGg">ici</a>.</p>
<p><em>Note</em> : En général, la meilleure solution si vous souhaitez juste envoyer des
images sur Mapillary est de prendre une image toutes les quelques secondes (2
secondes est un bon compromis en général, vous pouvez prendre moins d’images
pour économiser la batterie ou plus d’images pour capturer plus de détails) et
d’enregistrer les traces <span class="caps">GPX</span> avec une fréquence au moins aussi élevée.
L’utilisation de vidéos donne généralement des images de moins bonne qualité
en sortie, et son seul intérêt concret est d’avoir le film complet en cas d’accident.</p>
<p><strong>Mise à jour</strong> : <a href="https://josm.openstreetmap.de/"><span class="caps">JOSM</span></a> l’éditeur pour
<a href="http://openstreetmap.org/">OpenStreetMap</a> a un plugin pour gérer les
tags <span class="caps">GPS</span> dans les photos
<a href="https://wiki.openstreetmap.org/wiki/JOSM/Plugins/Photo_Geotagging">“photo_geotagging”</a>.
C’est le meilleur moyen que je connaisse à ce jour pour ajuster facilement et
(assez) rapidement la position de nombreuses photos avant envoi dans
Mapillary. Le même plugin permet aussi de faire correspondre les photos avec
une trace <span class="caps">GPX</span> (comme ce que font les scripts Mapillary précédents).</p>Des randonnées à vélo autour de Royan2018-08-20T19:17:00+02:002018-08-20T19:17:00+02:00Phykstag:localhost,2018-08-20:/Blog/output/2018/08/des-randonnees-a-velo-autour-de-royan.html<p>Il y a plusieurs véloroutes qui se croisent à Royan, l’occasion de faire
quelques balades sympas sur ces itinéraires. Voici quelques idées pour vous si
vous passez dans la région !</p>
<p>Il y a plusieurs véloroutes qui se croisent à Royan, l’occasion de faire
quelques balades sympas sur ces itinéraires. Voici quelques idées pour vous si
vous passez dans la région !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07294.JPG">
<img
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07294_mini.JPG" alt="Véloroute du tour de l'estuaire de Gironde, à Talmont-sur-Gironde." />
</a>
</p>
<h2>Quelques notes générales</h2>
<p>Les pistes cyclables dans les villes de la côte (Royan,
Saint-Georges-de-Didonne, Pontaillac et Vaux) sont assez mal conçues et
clairement pensées dans une optique “loisirs”. Les pistes conflictuelles
sont légion (pistes sur trottoir sans délimitation claire, zones de
rencontre saturées et autres “cyclistes, pied à terre”) et ne comptez donc
pas faire plus que 10km/h en moyenne sur ces infrastructures. À prendre en
compte dans le calcul de vos temps de trajet ! Il n’est pas vraiment
possible de passer sur la chaussée pour aller plus vite, celle-ci étant
généralement saturée et embouteillée.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/pistes-royan.jpg">
<img
style="max-width: 800px; max-height: 600px"
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/pistes-royan.jpg" alt="Pistes cyclables à Royan, très conflictuelles…" />
</a>
</p>
<p>Pour rejoindre Royan depuis Paris, il faut prendre le <span class="caps">TGV</span> depuis Paris
Montparnasse jusqu’à Angoulême ou Niort. De là, il faut prendre un <span class="caps">TER</span>
(direct) jusqu’à Royan. Le transport des vélos non-démontés nécessite une
réservation préalable pour le <span class="caps">TGV</span> (+10€ par vélo, 2 places vélos en tout
par rame de <span class="caps">TGV</span>, dans une voiture dédiée en bout de train, il vaut mieux s’y
prendre à l’avance) et est gratuit dans le <span class="caps">TER</span> (crochets pour suspendre à la
verticale au-dessus de strapontins, les <span class="caps">TER</span> sont a priori tous équipés même si
la signalétique n’est pas toujours présente sur les portes). Prendre de
préférence une correspondance par Niort qui a des correspondances <span class="caps">TGV</span>/<span class="caps">TER</span> soit
quai-à-quai soit par un passage souterrain équipé de rampes pour vélos. À
Angoulême, il semble que ce soit passage souterrain obligatoire en portant le
vélo dans l’escalier.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/tgv.jpg">
<img
style="max-width: 800px; max-height: 600px"
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/tgv.jpg" alt="Rame vélo dans le TGV Ouest." />
</a>
</p>
<p>À Paris Montparnasse, il y a un accès aux quais des <span class="caps">TGV</span> sans escalier ni
ascenseur possible par la rampe d’accès au <a href="https://www.openstreetmap.org/way/409799416#map=18/48.84045/2.31749">dépose-minute des
taxis</a>.
La rampe d’accès est fléchée “livraisons crédit agricole” et donne sur le
Boulevard de Vaugirard, entre la station essence et le <span class="caps">CIC</span>. En suivant la
rampe puis l’accès pompier, on arrive dans le hall des <span class="caps">TGV</span> (et des trains de
banlieue) sans avoir rencontré une seule marche !</p>
<p>À Royan, la gare est au niveau de la rue et il n’y a donc aucun problème avec
un vélo.</p>
<h2>L’EuroVélo 1 (la Vélodyssée) jusqu’à Soulac-sur-mer (20km aller/retour)</h2>
<p>Première balade, la plus courte, aller jusqu’à
<a href="https://www.openstreetmap.org/relation/161253">Soulac-sur-mer</a> en vélo, en
prenant le bac ! L’itinéraire est très bien fléché en suivant <a href="https://www.lavelodyssee.com/etapes/royan-soulac-sur-mer">la
Vélodyssée</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07281.JPG">
<img
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07281_mini.JPG" alt="Le bac" />
</a>
</p>
<p>Le bac part toutes les 45 minutes en moyenne de Royan et coûte 5€ pour un
passager avec un vélo. Il n’y a pas de stationnement prévu pour les vélos sur
le bac, ils sont empilés le long des rembardes, ne pas hésiter à monter parmis
les derniers et à s’écarter un peu des autres vélos si on a du bon matériel du
coup !</p>
<p>Attention, à la sortie du bac du côté du Verdon, il manque un panneau pour
suivre la Vélodyssée. Il faut en fait tourner à gauche sur la départementale
puis immédiatement à droite pour reprendre la <a href="https://www.openstreetmap.org/way/51363030">Cité des
Douanes</a>. L’itinéraire jusqu’à
Soulac est ensuite très agréable, essentiellement plat, bitumé et le long
d’une ancienne voie ferrée. C’est l’une des pistes cyclables du coin les plus
agréables !</p>
<p>En arrivant à Soulac, il vaut mieux se garer en retrait de la plage, par
exemple devant la basilique ou l’office de tourisme. Il y a plus de places et
de meilleurs arceaux. À voir à Soulac:</p>
<ul>
<li>La <a href="https://www.openstreetmap.org/way/192407363">basilique du 12e siècle</a></li>
<li>Les villas entre l’office de tourisme et la plage, dans les rues parallèles
autour de la <a href="https://www.openstreetmap.org/way/122725311">rue de la plage</a></li>
<li>La <a href="https://www.openstreetmap.org/node/5825822959">réplique de la statue de la Liberté</a></li>
<li><a href="https://www.openstreetmap.org/way/192415065">Le Signal</a>, une ancienne
résidence, construite à 200m de la mer en 1967, maintenant au bord de la
dune avec l’érosion du littoral. Elle est abandonnée depuis quelques
années et le centre d’une lutte judiciaire pour l’indemnisation des propriétaires.</li>
<li>La <a href="https://www.openstreetmap.org/node/1372974042">fontaine de la place Clémenceau</a></li>
<li>Il y a un itinéraire fléché de 8km autour de la ville faisant passer devant
la plupart des choses à voir.</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07279.JPG">
<img style="max-width: 30%; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07279_mini.JPG" alt="La basilique" />
</a>
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07276.JPG">
<img style="max-width: 30%; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07276_mini.JPG" alt="Les villas" />
</a>
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07274.JPG">
<img style="max-width: 30%; margin-left: 1em; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07274_mini.JPG" alt="Le Signal" />
</a>
</p>
<p>Pour le goûter, on a testé <a href="https://www.tripadvisor.fr/Restaurant_Review-g635777-d10911040-Reviews-Martine_A_La_Plage-Soulac_sur_Mer_Gironde_Nouvelle_Aquitaine.html">Martine à la
plage</a>,
mais il y a sûrement mieux. Ok pour un jus de fruit frais et une crêpe, plutôt
cher pour manger.</p>
<h2>L’Estuaire de la Gironde à vélo jusqu’à Talmont sur Gironde (40km</h2>
<p>aller/retour)</p>
<p>Deuxième balade pour aller jusqu’à <a href="https://www.openstreetmap.org/relation/126520">Talmont sur
Gironde</a>, un village qui a reçu
le label “Plus beaux villages de France”. L’itinéraire est très bien balisé,
en suivant la <a href="https://www.francevelotourisme.com/base-1/troncons/lestuaire-de-la-gironde-a-velo/etapes/lestuaire-de-la-gironde-a-velo-royan-st-fort">route de l’estuaire de la Gironde à
vélo</a>.</p>
<p>Dans Royan et Saint-Georges-de-Didonne, l’itinéraire est essentiellement en
bidirectionnelles sur trottoir (voir plus haut). En sortie de
Saint-Georges-de-Didonne, il y a un (bref) <a href="https://www.openstreetmap.org/way/324098163#map=16/45.5846/-0.9831&layers=C">passage sur la
D25</a>,
au milieu de la circulation automobile. Attention, cette partie est un peu
dangereuse (surtout si vous roulez avec des enfants), il y a beaucoup de
trafic et les voitures roulent vite ! L’itinéraire “officiel” fait bifurquer
ensuite sur un <a href="https://www.openstreetmap.org/way/59242826">petit chemin
forestier</a> (<span class="caps">VTC</span> / <span class="caps">VTT</span> recommandé).
Une alternative est de prendre <a href="https://www.openstreetmap.org/way/341223534#map=17/45.58171/-0.98274&layers=C">l’allée des
Paons</a>
qui permet de bifurquer plus tôt, à un croisement assez sécurisé et de rouler
sereinement sans <span class="caps">VTC</span>/<span class="caps">VTT</span>. Dans le sens du retour, suivre l’allée des Paons
permet aussi d’arriver à une vraie intersection avec la D25 pour s’insérer
dans le trafic.</p>
<p>L’itinéraire continue sur des routes à très faibles trafic et des voies entre
les champs jusqu’à l’entrée de
<a href="https://www.openstreetmap.org/relation/121737">Meschers-sur-Gironde</a>.</p>
<p><a href="https://www.openstreetmap.org/way/30104643">Le passage sur la corniche</a> est
super (sur la route, limitée à 30km/h, ne pas hésitez à rouler au milieu car
les voitures n’ont de toutes façons pas la place de doubler). C’est l’occasion
de faire un arrêt pour visiter les <a href="https://www.openstreetmap.org/node/2268694682">Grottes de
Régulus</a> (municipales) ou <a href="https://www.openstreetmap.org/node/2268694672">de Matata</a> (privées).</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07284.JPG">
<img
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07284_mini.JPG" alt="Le port de Meschers-sur-Gironde" />
</a>
</p>
<p>On arrive ensuite sur un <a href="https://www.openstreetmap.org/way/374717290">joli petit
port</a> avec <a href="http://www.lespavesbordelais.fr/2016/01/carrelets-estuaire-gironde/">des
carrelets</a>.</p>
<p>Entre Meschers et Talmont, la route est en voie verte dans le marais,
totalement isolé des voitures et vraiment top ! Une des meilleures sections de
pistes cyclables des balades de cet article !</p>
<p>Enfin, on arrive à Talmont-sur-Gironde, où le stationnement est assez
compliqué (que des places pour les voitures). Il y a un parking vélo
<a href="https://www.openstreetmap.org/node/2263141023">ici</a>, très vite saturé
(pinces-roues, 15 places). Les gens laissent leurs vélos attachés ensemble le
long des murets et ça ne semble pas trop craindre. Les vélos sont interdits
dans l’enceinte du village.</p>
<p style="text-align: center">
<a href="https://commons.wikimedia.org/wiki/File:Talmont-sur-Gironde_Vue_nord1.jpg">
<img
style="max-width: 800px; max-height: 600px"
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/Talmont-sur-Gironde_Vue_nord1.jpg" alt="Talmont-sur-Gironde (photo CC BY-SA 4.0, source Wikipédia)" />
</a>
</p>
<p>À Talmont, il ne faut pas rater <a href="https://www.openstreetmap.org/way/499460816">le
port</a>, la <a href="https://www.openstreetmap.org/way/43190369">place de la
Priauté</a> (place de la mairie) et
<a href="https://www.openstreetmap.org/way/78132547">l’Église Sainte-Radegonde et son
cimetière</a>. Attention, à Talmont,
tous les commerçants ne prennent pas la carte bleue et il n’y a pas de
distributeur de billet ! Il n’y a pas beaucoup de réseau téléphonique non plus.</p>
<p>On peut prolonger un peu en suivant l’itinéraire cyclable <a href="https://www.openstreetmap.org/way/91695971">sur la
falaise</a> pour profiter de la vue
et des vignobles.</p>
<h2>De Royan jusqu’à Marennes par l’EuroVélo 1 (la Vélodyssée) (45km aller)</h2>
<p>Cette fois-ci, on suit l’EuroVélo 1 dans l’autre sens, vers le Nord.</p>
<p>On traverse successivement Royan, Pontaillac (où un arrêt chez le glacier
<a href="https://www.openstreetmap.org/node/741696165">Lopez</a> est recommandé !),
Vaux-sur-mer et Saint-Palais-sur-mer. À part la très belle bidirectionnelle
cyclable entre Royan et Pontaillac, la plupart de cet itinéraire est en
trottoir partagé, à une allure très réduite. Pour traverser le centre de
Saint-Palais-sur-mer, l’itinéraire passe en zone de rencontre et la chaussée
est particulièrement embouteillée…</p>
<p>L’itinéraire continue ensuite jusqu’à la Grande côte sur une voie cyclable
séparée le long de la (bruyante et passante) <a href="https://www.openstreetmap.org/way/61995924">avenue de la Grande
Côte</a>. La vue depuis le parking au
bout de l’avenue est très sympa !</p>
<p>Entre la grande côte et la Palmyre, l’itinéraire passe en site propre à
travers la forêt. La route est bitumée mais le tracé est localement difficile
avec quelques montagnes russes et un peu de sable. Arrivé à la Palmyre, on
profite de la vue sur <a href="https://www.openstreetmap.org/node/5666097170">Bonne
Anse</a> et c’est l’occasion de
faire un arrêt pique-nique !</p>
<p>On repart ensuite à travers la forêt, en site propre, sur un tracé bitumé et
plat, jusqu’à Ronces-les-bains. Après avoir évité les piétons en début de
parcours, puis avoir joué aux montagnes russes, cette partie du trajet est
la plus agréable, avec un tracé idéal ! C’est aussi la moins fréquentée !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07299.JPG">
<img
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07299_mini.JPG" alt="Bonne-Anse à marée basse et le phare de la Coubre" />
</a>
</p>
<p>On aperçoit localement Bonne Anse au début, puis on peut faire un arrêt pour
visiter le <a href="https://www.openstreetmap.org/way/77448484">phare de la Coubre</a>.
En arrivant sur l’extrêmité nord, <a href="https://www.openstreetmap.org/relation/1860645">on peut
s’arrêter</a> et rejoindre la
plage la plus proche pour profiter de la très belle vue sur Marennes, l’ile
d’Oléron et son pont. On arrive finalement à Ronces-les-bains.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/oleron.jpg">
<img
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/oleron_mini.jpg" alt="Vue sur Oléron depuis un eplage proche de la piste cyclable" />
</a>
</p>
<p>L’itinéraire cyclable ne fait que longer Ronces-les-bains, en la contournant.
Il y a pourtant un <a href="https://www.openstreetmap.org/node/3241985052">point accueil
vélo</a> (toilettes, eau potable,
stationnement vélo, informations touristiques, etc.), des commerces et une
jolie vue depuis la plage sur Oléron et Marennes.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/ronces.jpg">
<img
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/ronces_mini.jpg" alt="Panorama à Ronces-les-bains" />
</a>
</p>
<p>La fin de l’itinéraire, entre Ronces-les-bains et Marennes est clairement très
décevante et de loin la plus désagréable des sections cyclables de cet
article. Heureusement, il n’y a que 7km ! L’itinéraire cyclable longe la (très
passante et très bruyante)
<a href="https://www.openstreetmap.org/way/140668924">D728</a>. La voie cyclable est
séparée par quelques mètres de gazon, mais n’est quand même pas très agréable…</p>
<p>Attention (notamment avec des enfants) à la traversée du <a href="https://www.openstreetmap.org/way/32766191">pont sur la
Seudre</a>, sur lequel la piste
cyclable disparaît purement et simplement ! Deux options : rouler sur le
bas-côté (étroit et avec les voitures qui ne ralentissent pas) ou pousser son
vélo (ce qui est plus sécurisé, mais nécessite de rester beaucoup plus
longtemps sur le pont).</p>
<p>Finalement, l’itinéraire recommence à emprunter des voies vertes le long des
marais en arrivant à Marennes, ce qui est nettement plus agréable !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07342.JPG">
<img
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07342_mini.JPG" alt="L'église de Marennes" />
</a>
</p>
<p>À Marennes, on pourra voir <a href="https://www.openstreetmap.org/way/121284294">l’Église
Saint-Pierre</a>, le <a href="https://www.openstreetmap.org/way/177680385#map=17/45.81939/-1.11025">petit port de
plaisance</a>
et son chenal (attention à bien être du bon côté du chenal pour la suite de
votre parcours, il n’est pas aisé de le traverser !), la <a href="https://www.openstreetmap.org/relation/5703795">Cité de
l’Huître</a> où passent un
certain nombre d’itinéraires cyclables dans les marais et enfin le <a href="https://www.openstreetmap.org/node/1704502006">Port de la
Cayenne</a> à l’autre extrémité du
chenal, à l’embouchure avec la Seudre.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07345.JPG">
<img
src="http://localhost/Blog/output/images/2018/08/randos_velo_royan/DSC07345_mini.JPG" alt="Dans les marais vers la cité de l'Huitre" />
</a>
</p>
<p>Une autre possibilité, non testée ici, est de passer par <a href="https://www.openstreetmap.org/relation/121742#map=12/45.7119/-1.0272">Mornac sur
Seudre</a>,
un joli petit village et un port sur la Seudre. De là, il y a des <a href="http://www.geovelo.fr/la-rochelle/rides/487/Les-chemins-de-la-Seudre">itinéraires
cyclables</a>
sur des voies à faibles circulation à travers les marais qui rejoignent
Marennes. C’est un peu plus court en distance, et le trajet entre Royan et
Mornac peut se faire <a href="https://www.geovelo.fr/la-rochelle/itinerary/search?profile=MEDIAN&bikeType=TRADITIONAL&wayPoints=45.62306,-1.04306%7C45.70972,-1.02833">assez
aisément</a>
en suivant les routes à faible circulation (déjà testé et validé !), même en
l’absence d’itinéraires cyclables clairement fléchés ! On n’échappe pas au
pont sur la Seudre juste avant Marennes par contre :/</p>
<p>Il n’y a malheureusement pas de laison de transports en commun entre Marennes
et Royan qui permettent d’emporter un vélo (à ma connaissance). Il faut donc
soit un véhicule à Marennes, soit faire le trajet aller-retour. Une autre
possibilité est de suivre l’EuroVélo 1 jusqu’à
<a href="https://www.openstreetmap.org/relation/117888">Rochefort</a> d’où on peut
rentrer à Royan en <span class="caps">TER</span> en 1h15 (avec correspondance à Saintes) pour moins de
10€ (tarif jeunes). À noter qu’il est possible de gagner quelques kilomètres
en évitant la grande boucle de l’EuroVélo 1 en arrivant sur Rochefort et en
déviant par
<a href="https://www.openstreetmap.org/relation/1074638#map=13/45.9022/-0.9555">Échillais</a>
puis par le <a href="https://www.openstreetmap.org/way/25622734">Pont transbordeur du
Matrou</a> (voir aussi <a href="https://www.pont-transbordeur.fr/infos-pratiques">ici</a>). Le pont est actuellement en travaux mais le passage avec un vélo est possible avec les navettes fluviales <a href="http://riveo-rochefortocean.com/">Rivéo</a> pour 1.6€ (pour un passager et son vélo).</p>10 jours au Portugal, de Porto à Lisbonne2018-06-17T21:12:00+02:002018-06-17T21:12:00+02:00Phykstag:localhost,2018-06-17:/Blog/output/2018/06/10-jours-au-portugal-de-porto-a-lisbonne.html<p>On continue la série des notes de voyage avec un programme pour 10 jours au Portugal, de Porto à Lisbonne. Au programme : Porto, Coimbra, les monastères classés au patrimoine de l’<span class="caps">UNESCO</span>, la côte atlantique, Sintra et Lisbonne !</p>
<p>On continue la série des notes de voyage avec un programme pour 10 jours au Portugal, de Porto à Lisbonne. Au programme : Porto, Coimbra, les monastères classés au patrimoine de l’<span class="caps">UNESCO</span>, la côte atlantique, Sintra et Lisbonne !</p>
<h2>Vendredi : Porto (à pied)</h2>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06220.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06220_mini.JPG" alt="Le pont Dom Luis et la vieille ville" />
</a>
</p>
<p>Départ de Paris avec 2h de retard (merci Transavia !), puis 2h de vol et nous voici arrivée à Porto à 14h. Bon à savoir : si vous avez plus de 2h de retard, vous avez le droit à une carte de restauration, à retirer à un guichet de Transavia (à Orly, c’était 3€ / personne valable dans les boutiques de l’aéroport, ça nous a payé un café). On a eu du bol, un ami qui faisait le même trajet avec RyanAir a eu son vol purement et simplement annulé, un aller-retour à Beauvais pour rien et les vacances perdues… Attention aux <em>low costs</em> :(</p>
<p>À Porto, l’aéroport est sur le réseau de transport en commun. Il faut prendre un billet Z4 à l’automate (environ 2€, correspondant à un nombre de zones à traverser) puis la ligne de métro/tram violette pour rejoindre le centre (compter 45 minutes). Les tickets sont à charger sur une carte magnétique rechargeable (“Andante”, environ 50 centimes à rajouter au prix du premier billet acheté pour obtenir la carte). Il n’y a pas de remboursement de la carte en guichet lorsque vous partez.</p>
<p>Porto n’est pas très étalée, et tout peut assez facilement se visiter à pied. L’après-midi est consacré à la visite du centre ville de Porto. On est passé devant pas mal de monuments en hésitant à rentrer, et on s’est dit qu’on le ferait probablement le lendemain (le samedi) si on avait le temps. Grave erreur ! Il n’y avait presque aucune file d’attente le vendredi après-midi, et c’était monstrueux le samedi !</p>
<p>Un trajet pour faire un gros tour est visible <a href="https://maps.openrouteservice.org/directions?n1=41.144027&n2=-8.609548&n3=16&a=41.150624,-8.610029,41.149971,-8.606359,41.149981,-8.605707,41.145462,-8.609375,41.145822,-8.614024,41.146904,-8.614765,41.142845,-8.611181,41.142481,-8.60917,41.140152,-8.609486,41.140954,-8.615563,41.150624,-8.610029&b=2&c=0&g1=-1&g2=0&k1=fr&k2=km">ici</a>. Vous verrez</p>
<ul>
<li>La <a href="https://www.openstreetmap.org/way/26119759#map=18/41.15082/-8.60541">Rua de Santa Catarina</a>, rue piétonne et commerçante.</li>
<li>La <a href="https://www.openstreetmap.org/way/365610859">Capela das Almas</a> et sa magnifique façade couverte d’<a href="https://fr.wikipedia.org/wiki/Azulejos"><em>azulejos</em></a>.</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06120.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06120_mini.JPG" alt="La Capela das Almas, dans la Rua de Santa Catarina" />
</a>
</p>
<ul>
<li>Le <a href="https://www.openstreetmap.org/relation/3046626">marché do Bolhão</a> est à voir apparemment, mais il est fermé pour travaux en ce moment (mai 2018).</li>
<li>La gare de <a href="https://www.openstreetmap.org/way/331655260">São Bento</a> et ses fresques d’<em>azulejos</em> dans le hall.</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06121.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06121_mini.JPG" alt="La gare de São Bento" />
</a>
</p>
<ul>
<li>La <a href="https://www.openstreetmap.org/way/215135702">Praça da Liberdade</a> et le magnifique bâtiment art déco du <a href="https://www.openstreetmap.org/node/1278714045">Mc Donald’s</a> sur la place.</li>
<li>L’<a href="https://www.openstreetmap.org/way/223780953">Igreja dos Clérigos</a> (plus d’infos <a href="https://fr.wikipedia.org/wiki/Tour_des_Clercs">ici</a>), très belle. Entrée gratuite, possibilité de monter dans les tours (pour environ 5€, on doit avoir une belle vue d’en haut), on ne l’a pas fait le vendredi et le samedi il y avait plus d’une heure d’attente.</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06198.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06198_mini.JPG" alt="La tour de l'Igreja dos Clérigos" />
</a>
</p>
<ul>
<li>La <a href="https://www.openstreetmap.org/way/229270821">librairie Lello</a> (voir <a href="https://fr.wikipedia.org/wiki/Librairie_Lello">plus d’infos</a>). Entrée assez chère (5€ / personne), déductibles d’un livre si vous en achetez un (un bon par livre). On n’est pas rentré mais on est allé voir <a href="https://www.openstreetmap.org/node/2730097912">A vida portuguesa</a> à côté, dans un joli bâtiment aussi et en entrée libre.</li>
<li>La <a href="https://www.openstreetmap.org/way/210461448">cathédrale de Porto</a> (voir <a href="https://fr.wikipedia.org/wiki/Cath%C3%A9drale_de_Porto">plus d’infos</a>), un des bâtiments les plus anciens de la ville, de style roman et très sobre en comparaison des autres églises de la ville :)</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06143.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06143_mini.JPG" alt="La façade de la cathédrale de Porto" />
</a>
</p>
<ul>
<li>L’impressionnant <a href="https://www.openstreetmap.org/way/31572985">Pont Dom Luis</a> (voir aussi <a href="https://fr.wikipedia.org/wiki/Pont_Dom-Lu%C3%ADs">ici</a>) sur le Douro.</li>
<li>Caché au fond d’une place derrière la cathédrale, il y a l’<a href="https://www.openstreetmap.org/way/238893532">Igreja de Santa Clara</a>. Actuellement en travaux, elle a des horaires d’ouverture assez obscurs. On a réussi à y aller le lendemain, et c’est <strong>magnifique</strong> (et le gardien discute et explique tout !) (quelques explications en portugais et photos <a href="https://pt.wikipedia.org/wiki/Igreja_de_Santa_Clara_(Porto)">ici</a>).</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06151.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06151_mini.JPG" alt="L'entrée de l'Igreja de Santa Clara, cachée au fond d'une place" />
</a>
</p>
<ul>
<li>La <a href="https://www.openstreetmap.org/relation/2880925">Casa do Infante</a>, une ancienne maison de douanes qui abrite un musée (archéologique) sur la ville de Porto. Entrée gratuite le weekend, ça vaut le coup de s’y arrêter rapidement si vous passez devant. Voir aussi <a href="https://en.wikipedia.org/wiki/Casa_do_Infante">ici</a> (en anglais).</li>
<li>L’<a href="https://www.openstreetmap.org/way/210681249">Igreja São Francisco</a> qui se visite (entrée payante 4€, couplée avec le musée dans le bâtiment en face). La visite commence par les catacombes et l’ossuaire dans le bâtiment en face (brrr !) puis continue dans l’église richement décorée. Il y aurait 600kg d’or pour recouvrir les boiseries à l’intérieur ! Voir aussi <a href="https://fr.wikipedia.org/wiki/%C3%89glise_Sao_Francisco_(Porto)">ici</a>.</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06193.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j1/DSC06193_mini.JPG" alt="Un exemple de dorure dans l'Igreja São Francisco" />
</a>
</p>
<ul>
<li>Les rues typiques du vieux Porto, notamment dans le bas Porto sur les quais et au pied de la cathédrale.</li>
<li>De nombreuses églises, toutes plus belles et impressionnantes les unes que les autres.</li>
<li>On n’y est pas allé mais il y a le <a href="https://www.openstreetmap.org/node/2478836067">palais de la Bourse</a> (ancien bâtiment de la bourse de Porto) qui est à côté de l’église São Francisco et vaut apparemment le coup.</li>
</ul>
<p>On a pris un goûter à la <a href="https://www.openstreetmap.org/node/4387372589">Confeitaria Tamisa</a>, qui était pas mal et où on a découvert la <a href="http://www.marmiton.org/magazine/diaporamiam_patisseries-portugaises_7.aspx">Bola Berlim</a> (un beignet fourré à la crème pâtissière). Les <em>pasteis de nata</em> étaient pas mal aussi, jus d’orange frais et prix raisonnables.</p>
<p>Le soir, on a mangé à <a href="https://www.openstreetmap.org/node/5656385722">Novo Mondo</a>, une petite cantine proposant des formules (différentes chaque jour) soupe + plat + dessert + café pour 5 à 7€ (selon le plat). Boisson à payer en supplément, comme toujours au Portugal (voir en fin d’article). Ils faisaient par exemple de la côte de porc grillée, de la <em>feijoada de mariscos</em> (sorte de cassoulet avec des haricots blancs, des fruits de mer et du poisson) ou des sardines grillées (par deux !) et de la salade de fruits frais ou mousse au chocolat ou crème vanille en dessert. Très copieux ! Seul point faible, étant conseillé par le Routard, il n’y a que des français… :(</p>
<p>À Porto, on est resté dormir dans le <a href="https://www.airbnb.fr/rooms/11601918">Airbnb de Miguel</a> bien situé et très bon rapport qualité / prix !</p>
<h2>Samedi : Porto (à pied)</h2>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j2/DSC06165.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j2/DSC06165_mini.JPG" alt="Les bateaux de transport du Porto et les caves" />
</a>
</p>
<p>Le lendemain matin, on décide d’aller explorer l’autre rive du Douro, du côté de Vila Nova de Gaia et des célèbres caves de Porto. De l’autre côté du Pont Dom Luis, il y a un joli <a href="https://www.openstreetmap.org/node/1670330650#map=17/41.13764/-8.60887">point de vue</a> sur le fleuve et le pont.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j2/DSC06223.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j2/DSC06223_mini.JPG" alt="Vue sur Porto, le Douro et la promenade le long du Douro" />
</a>
</p>
<p>La plupart des caves les plus célèbres sont sur l’<a href="https://www.openstreetmap.org/way/326594065#map=17/41.13738/-8.61525">Avenida Ramos Pinto</a> (attention, ça descend bien entre le point de vue et les quais !) : <a href="https://www.openstreetmap.org/way/382530398">Sandeman</a>, <a href="https://www.openstreetmap.org/node/4411417990">Calem</a>, <a href="https://www.openstreetmap.org/node/4948512222">Cruz</a>, <a href="https://www.openstreetmap.org/node/4462899090">Ramos Pinto</a> et <a href="https://www.openstreetmap.org/node/4924697822">Ferreira</a>. Toutes proposent des formules similaires avec visite et dégustation (autour de 15€ avec dégustation de trois portos). Des boutiques vendent des bouteilles dans chaque cave, à des prix assez similaires aux prix habituels (ni franchement moins chers ni plus chers que ce qu’on trouve ailleurs ou en France). Ne buvant pas d’alcool, je ne pourrais pas vous conseiller plus sur la meilleure des caves :)</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j2/DSC06232.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j2/DSC06232_mini.JPG" alt="Du street-art du côté des caves" />
</a>
</p>
<p>Le midi, on est allé manger une <a href="https://fr.wikipedia.org/wiki/Francesinha"><em>francesinha</em></a> (sorte de croque-monsieur en sauce) chez <a href="https://www.openstreetmap.org/node/5657097523">Sancho Panza</a> qu’on nous avait recommandé. La <em>francesinha</em> était bonne et il y a une grande terrasse avec vue sur le Douro qui est très agréable mais le restaurant est très touristique (pas très authentique et avec des prix plutôt chers pour Porto).</p>
<p>L’après-midi, on a voulu aller à <a href="https://www.openstreetmap.org/relation/5936090">Foz de Douro</a>, à l’embouchure du Douro. C’est un peu loin (7 km) mais il est possible de louer un vélo, de prendre le bus (<a href="http://www.stcp.pt/en/travel/lines/?linha=500">bus 500</a> qui va de Porto à Foz de Douro puis le long de la côte) ou de prendre <a href="http://www.stcp.pt/en/travel/lines/?linha=1">le tram</a>. On a décidé de prendre le tramway et (comme d’habitude) on est tombé en plein milieu d’un événement spécial sans le vouloir ! C’était un jour spécial avec un défilé de vieux tramways, du coup la circulation était ralentie et moins régulière. En échange, on a pu monter dans un vieux tramway (de 1927 !) et le billet était valable toute la journée en échange. Si vous prévoyez d’y aller en bus 500, deux choses à noter : les horaires prévus sont très optimistes et le weekend, <strong>tous</strong> les portuans vont à la plage et les bus sont saturés ! Il y a une grande promenade tout le long du Douro (de Porto à Foz de Douro) qui continue le long de l’océan. En repartant le soir, tous les bus étaient pleins à craquer et avec le défilé, les tramways étaient très irréguliers et pleins aussi, du coup on est rentré le long du Douro à pied. C’est loin, mais la balade est très agréable, au bord du fleuve !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j2/DSC06267.JPG">
<img style="max-width: 40%; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j2/DSC06267_mini.JPG" alt="Foz de Douro" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j2/DSC06268.JPG">
<img style="max-width: 40%; margin-left: 1em; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j2/DSC06268_mini.JPG" alt="Le tramway pour Foz de Douro, qui zigzague entre les voitures en stationnement !" />
</a>
</p>
<p>Le soir, on a mangé au <a href="https://www.openstreetmap.org/way/229210123">O Ernesto</a>, un très bon restaurant à des prix raisonnables (compter environ 15€ par personne à la carte tout compris). Pas mal de choix de cuisine portugaise (<em>bacalhau</em> (morue), poisson frais, <em>cabrito</em> (chèvre)). Penser à prendre une demi-portion pour avoir une portion française normale ! :) On est allé prendre un verre au <a href="https://www.openstreetmap.org/node/5657135213">Café Lusitano</a> après, qui avait l’air sympa mais on y était probablement <strong>beaucoup</strong> trop tôt et il n’y avait pas beaucoup d’ambiance. En plus, c’était un soir de finale de foot… À noter qu’il semblerait qu’il soit interdit de jouer à des jeux (de société) dans un bar au Portugal (c’est illégal), même s’il n’y a pas d’argent en jeu. En sortant, Porto avait gagné la finale de la compétition nationale de foot, et <strong>tous</strong> les portuans avaient sauté dans leur voiture à minuit pour klaxonner dans les rues ! Gros bouchons dans toute la ville et nuit courte…</p>
<h2>Dimanche : Porto - Bussaco - Coimbra (en voiture, ±2h de route, 150km)</h2>
<p style="text-align: center">
<a href="https://maps.openrouteservice.org/directions?n1=40.680117&n2=-8.12233&n3=10&a=41.16106,-8.614032,40.635013,-8.651136,40.39025,-8.385003,40.200597,-8.42868&b=0&c=0&k1=fr-FR&k2=km">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j3/j3.png"
alt="Trajet le dimanche" />
</a>
</p>
<p>Le trajet est visible
<a href="https://maps.openrouteservice.org/directions?n1=40.680117&n2=-8.12233&n3=10&a=41.16106,-8.614032,40.635013,-8.651136,40.39025,-8.385003,40.200597,-8.42868&b=0&c=0&k1=fr-FR&k2=km">ici</a>.</p>
<p>Le programme initial était d’aller à Bussaco puis de passer la fin de journée à visiter Coimbra, mais notre hôte du soir, à Coimbra, nous a prévenu qu’il y avait des défilés et des célébrations étudiantes (imaginez le 14 juillet avec des étudiants à la place des militaires) dans toute la ville ce jour, pour marquer la fin de l’année, et qu’il valait donc mieux arriver après 19h. Cela expliquait pourquoi on avait croisé autant de jeunes avec des costumes et des capes à la Harry Potter la veille à Porto ! :) Du coup, on a traîné en chemin pour arriver le plus tard possible à Coimbra (et la circulation était effectivement impossible en voiture à proximité du centre ville, peu de stationnement disponible et un monde fou (alcoolisé) dans la ville quand on est arrivé à 19h).</p>
<p>Premier arrêt en chemin à <a href="https://www.openstreetmap.org/node/2912652994#map=14/40.6381/-8.6452">Aveiro</a>, un ancien petit port aujourd’hui au fond d’une lagune, avec des canaux qui lui donne un air de petite Venise (<a href="https://fr.wikipedia.org/wiki/Aveiro">plus d’infos</a>). C’est aussi dans cette ville qu’on trouve les <a href="https://pt.wikipedia.org/wiki/Ovos_moles_de_Aveiro"><em>ovos moles</em></a>, de délicieuses petites pâtisseries au jaune d’œuf (avec <strong>beaucoup</strong> de jaune d’œuf). On a trouvé à se garer gratuitement <a href="https://www.openstreetmap.org/way/504775639">ici</a>, il y avait pas mal de stationnement gratuit dans ce coin de la ville, à 10/15 minutes de marche des canaux. C’est à peu près la limite de zone de stationnement payant, le stationnement est payant au niveau du tribunal par exemple. Outre les canaux et le centre ville, il y a aussi un <a href="https://www.openstreetmap.org/way/280348854#map=16/40.6409/-8.6573">éco-musée</a> dans les marais. Si vous passez au <a href="https://www.openstreetmap.org/node/1799584360">musée d’art nouveau</a>, vous pourrez récupérer une carte d’Aveiro avec les bâtiments remarquables de style art nouveau (gratuit, mais il faut demander à la caisse pour l’avoir), pratique ! On a mangé à la <a href="https://www.openstreetmap.org/node/2808876965">Pastelaria Rainha d’Aveiro</a> qui était un peu au bout du monde, mais d’un très bon rapport qualité / prix (et avec d’excellents <em>ovos moles</em> !). Ils servent des assiettes avec salade, crudité, riz et hamburger, saucisse, omelette etc., excellents desserts. Compter 5 à 10€ par personne avec boisson, dessert et café. Clientèle très locale, on en avait marre d’entendre du français partout :) Pour prolonger un peu la visite d’Aveiro, il y a aussi le <a href="https://www.openstreetmap.org/way/160090666">musée d’Aveiro</a> qui avait l’air sympa (mais on n’a pas eu le temps d’y aller).</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j3/DSC06270.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j3/DSC06270_mini.JPG" alt="Les canaux d'Aveiro" />
</a>
</p>
<p>Après manger, direction <a href="https://www.openstreetmap.org/way/109916422#map=15/40.3755/-8.3679">Buçaco</a> (ou Bussaco, j’ai l’impression qu’il n’y a pas vraiment d’orthographe fixe), une grande forêt (à mi-chemin entre une forêt et un parc) appartenant autrefois à une congrégation de moines. Le monastère a depuis été transformé en <a href="https://www.openstreetmap.org/way/122573094">hôtel</a>. C’est en haut d’une butte, accrochez-vous pour atteindre l’entrée si vous décidez de suivre les raccourcis de Waze :) L’accès à la forêt est payant 5€ pour les voitures (gratuit pour les piétons, mais il est assez difficile de se garer en dehors). Ce n’est pas forcément très clair en arrivant (et il n’y a pas vraiment de carte ni d’indication à l’entrée) mais le mieux est d’arriver par <a href="https://www.openstreetmap.org/node/240359398">Luso</a> (ou <a href="https://www.openstreetmap.org/node/1365714355">ici</a>), puis de se garer dès qu’on trouve de la place. On peut alors suivre les pancartes pour aller voir la <a href="https://www.openstreetmap.org/way/128913291">Vale dos Fetos</a> (vallées de fougères de Nouvelle-Zélande), puis remonter la <a href="https://www.openstreetmap.org/node/1369289604">Fonte Fria</a> (une magnifique fontaine en escaliers) puis <a href="https://www.openstreetmap.org/way/110097298">les bâtiments de l’ancien couvent</a> désormais transformé en hôtel (candidats au patrimoine mondial de l’<span class="caps">UNESCO</span>). On aperçoit l’intérieur par les fenêtres mais on ne peut malheureusement pas rentrer dans l’hôtel (sauf à aller au restaurant, fort cher :)). Parking possible à côté de l’hôtel aussi. Les plus courageux pourront suivre le chemin de croix. Il y a quelques chapelles représentants des scènes de la passion du Christ en chemin, puis on arrive à la <a href="https://www.openstreetmap.org/node/1365686255">Cruz Alta</a> où il y a un magnifique point de vue sur la région ! On peut aussi y aller en voiture mais c’est tricher !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j3/DSC06330.JPG">
<img style="max-width: 40%;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j3/DSC06330_mini.JPG" alt="Bussaco" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j3/DSC06293.JPG">
<img style="max-width: 40%; margin-left: 1em;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j3/DSC06293_mini.JPG" alt="Fonte Fria" />
</a>
</p>
<p>En arrivant à Coimbra, dernière étape de la journée en attendant que le cortège étudiant soit passé et que les rues soient rouvertes à la circulation : la <a href="https://www.openstreetmap.org/node/2829461375#map=17/40.19858/-8.43332">Quinta das Lagrimas</a> (entrée par <a href="https://www.openstreetmap.org/node/2458439915">ici</a>). Les quintas sont de grandes propriétés (souvent d’anciennes fermes) transformées en hôtels assez luxueux. La Quinta das Lagrimas est donc un hôtel luxueux (avec terrain de golf etc.), dont <a href="http://www.fundacaoinesdecastro.com/index.php/jardim/visitas.html">une partie des jardins est accessible au public</a> (entrée à 2€50). On peut se balader dans les jardins (très reposants), voir la <a href="https://www.openstreetmap.org/node/2829461375">Fonte dos Amores</a> et la <a href="https://www.openstreetmap.org/node/2829462029">Fonte das Lágrimas</a>, témoins d’une <a href="https://fr.wikipedia.org/wiki/Quinta_das_L%C3%A1grimas">histoire d’amour impossible</a> à la Shakespeare entre le prince Pedro (ancien roi du Portugal) et Inês de Castro (servante de sa femme). Inês a été assassinée à la Quinta das Lagrimas et la couleur rouge des rochers de la Fonte das Lágrimas serait due au sang versé, selon la légende. Pas très loin, il y a aussi un <a href="https://www.openstreetmap.org/way/60809395">ancien monastère</a> qui a été détruit par de multiples crues de la rivière voisine, puis reconstruit <a href="https://www.openstreetmap.org/relation/3348654">un peu plus loin</a>. On voit l’ancien monastère depuis l’extérieur (et depuis l’université), la visite (environ 4€) est à réserver aux amateurs de vieilles ruines :) Le nouveau monastère (qui date du XVIIe siècle quand même !) se visite aussi (entrée autour de 2€), mais on n’y est pas allé.</p>
<p>Finalement, les rues les plus extérieures sont de nouveau praticables et on peut prendre la direction de notre Airbnb pour la soirée : chez <a href="https://www.airbnb.fr/rooms/2098239">Fatima</a> (super bien situé, super rapport qualité / prix !). Le soir, on tente d’aller manger en ville, sans succès… Il y avait encore plus de monde qu’au 14 juillet à Paris, on a l’impression d’être en soirée étudiante avec le sol qui colle et il est impossible de traverser la place centrale. En plus, le dimanche soir pas mal de trucs sont fermés. Du coup, on se rabat sur le supermarché le plus proche et on visitera Coimbra le lendemain !</p>
<h2>Lundi : Coimbra - Tomar - Fatima (en voiture, ±2h de route, 120km)</h2>
<p style="text-align: center">
<a href="https://maps.openrouteservice.org/directions?n1=39.843604&n2=-8.498268&n3=11&a=40.200597,-8.42868,39.60505,-8.405413,39.608124,-8.442461,39.640529,-8.591566,39.632281,-8.67104&b=0&c=0&k1=fr-FR&k2=km">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/j4.png"
alt="Trajet le lundi" />
</a>
</p>
<p>Le trajet est visible
<a href="https://maps.openrouteservice.org/directions?n1=39.843604&n2=-8.498268&n3=11&a=40.200597,-8.42868,39.60505,-8.405413,39.608124,-8.442461,39.640529,-8.591566,39.632281,-8.67104&b=0&c=0&k1=fr-FR&k2=km">ici</a>.</p>
<p>Le lendemain matin, on décide de visiter quand même Coimbra avant de partir pour Tomar. Ouf, tous les étudiants dorment encore et on peut se promener dans les rues ! Direction le <a href="https://www.openstreetmap.org/node/2117270107#map=17/40.20809/-8.42894">plateau de l’Université</a>, sur la colline en centre ville (attention, ça monte !). L’idéal à pied est de passer par la <a href="https://www.openstreetmap.org/way/15228018">Rua Visconde da Luz</a> puis de monter par la rue <a href="https://www.openstreetmap.org/way/116224908">Quebra Costas</a> (littéralement “casse côtes”, vous êtes prévenus !), ou de faire le tour par la <a href="https://www.openstreetmap.org/way/255867953">Rua de Sobre Ribas</a>, moins pentue et qui permet de passer devant d’autres bâtiments anciens et remarquables. L’achat des billets pour la visite de l’Université se fait <a href="https://www.openstreetmap.org/node/5154054481">ici</a> (attention, pas mal de queue ! mais ça avance assez vite). Visite assez chère (12€ / personne, 10€ en tarif réduit), mais qui vaut le coup. Il y a plusieurs <a href="http://www.uc.pt/en/informacaopara/visit/pricelist">programmes</a> proposés, mais seul le premier programme, qui inclut la bibliothèque est vraiment bien. La visite de la bibliothèque se fait par petits groupes (et en temps limité) et un horaire de passage vous sera donné en prenant les billets. Le programme 2 (sans la bibliothèque) peut être une bonne option néanmoins si vous ne pouvez pas visiter la bibliothèque.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/DSC06361.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/DSC06361_mini.JPG" alt="L'université de Coimbra" />
</a>
</p>
<p>Il y a une plaquette disponible (gratuitement et en français) qui est vraiment très complète pour faire une visite autonome. La visite de l’Université inclut :</p>
<ul>
<li>Le <a href="https://www.openstreetmap.org/way/51292671">Museu da Ciência</a>, un petit musée du même genre que le Palais de la Découverte. Visite assez rapide (30 mins). Un guide vous accompagnera ensuite dans le <a href="https://www.openstreetmap.org/node/2913524396">Colégio de Jesus</a>, à l’arrière de <a href="https://www.openstreetmap.org/relation/2334830">la nouvelle cathédrale</a>. C’est à mon avis la partie la plus intéressante du musée, avec une importante collection d’instruments scientifiques d’époque (un peu comme le musée des arts et métiers à Paris) et une immense collection d’histoire naturelle (animaux empaillés et squelettes principalement, mais aussi beaucoup de coquillages) (compter 30 mins de plus).</li>
<li>Le <a href="https://www.openstreetmap.org/way/115744958">Palais Royal</a> et notamment la magnifique salle des actes (dans laquelle les thèses de l’Université de Coimbra sont toujours soutenues, en suivant la tradition), visite qui se finit avec un super point de vue sur la ville dans la <a href="https://www.openstreetmap.org/way/115574903">tour de l’horloge</a> (attention si vous avez le vertige mais vous pouvez sortir du palais sans passer par la tour de l’horloge).</li>
<li>La très belle chapelle baroque de <a href="https://www.openstreetmap.org/node/1358350574">São Miguel</a>, où l’on notera la symétrie parfaite (et le faux orgue pour maintenir la symétrie).</li>
<li>La <a href="https://www.openstreetmap.org/way/51293313">bibliothèque Janine</a>, le clou de la visite. L’entrée a récemment été déplacée et se fait maintenant par une porte dans <a href="https://www.openstreetmap.org/way/115575536">ces escaliers</a>, à l’heure indiquée sur votre billet. On rentre d’abord dans la prison académique (où était emprisonné les personnels de l’Université commettant des délits), puis on monte au demi-étage qui servait de réserve dans le passé avant d’entrer dans la bibliothèque en elle-même. On a un temps limité dans la bibliothèque et les photos sont interdites. La bibliothèque est magnifique, on notera les trois salles aux couleurs différentes ainsi que les rangements pour les échelles, camouflées dans les montants des étagères. Les livres sont préservés selon des processus naturels (aucune climatisation etc.). On notera également les grilles devant les étagères. La nuit, les bibliothécaires ouvrent les fenêtres pour que les chauve-souris rentrent et mangent les mites et insectes qui pourraient abimer les livres. Les grilles empêchent les chauve-souris de rester cachées dans l’obscurité derrière les livres.</li>
</ul>
<p>S’il vous reste un peu de temps, vous pouvez aller voir <a href="https://www.openstreetmap.org/relation/2334830#map=19/40.20991/-8.42466">la nouvelle cathédrale</a> (entrée payante, environ 1€) et l’<a href="https://www.openstreetmap.org/way/41222810">ancienne cathédrale</a> (entrée payante, environ 2.5€).</p>
<p>Pour manger le midi, on est allé à l’<a href="https://www.openstreetmap.org/node/2293584788">Adega do Paço do Conde</a>. Un restaurant avec pleins de salles reliées par une terrasse centrale qui ne paie absolument pas de mines à l’entrée. L’entrée est même franchement pas accueillante. Pourtant, les salles derrière sont très bien, on y mange du poisson frais ou des brochettes grillées au barbecue pour un prix très raisonnable (les desserts sont moins bien par contre). Compter entre 5 et 10€ par personne pour un plat, un dessert, les boissons et du café.</p>
<p>On reprend la route après manger, direction le <a href="https://www.openstreetmap.org/relation/6826254">Convento de Cristo</a> à <a href="https://www.openstreetmap.org/relation/6483070#map=13/39.5978/-8.3977">Tomar</a> (ancien monastère, inscrit au patrimoine mondial de l’<span class="caps">UNESCO</span>). Une visite à ne pas manquer ! On peut se garer <a href="https://www.openstreetmap.org/way/95600121">devant le monastère</a> ou <a href="https://www.openstreetmap.org/way/292069180">en ville</a>, c’est le même prix (parcmètres, pas très cher). Si vous vous êtes garés en ville, vous pouvez suivre le <a href="https://www.openstreetmap.org/way/94829163">chemin piéton</a> (attention, ça monte !), qui vous fera passer à côté de la chapelle <a href="https://www.openstreetmap.org/node/1108458921">Nossa Senora da Conceição</a> et de son point de vue sur la ville.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/DSC06415.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/DSC06415_mini.JPG" alt="Le convento da Cristo" />
</a>
</p>
<p>Si vous comptez visiter les autres monastères inscrits au patrimoine mondial de l’<span class="caps">UNESCO</span> (Batalha et Alcobaça, voir plus bas), pensez à prendre un billet combiné à l’entrée du Covento de Cristo (15€ pour les trois monastères, valide 7 jours, 50% de réduction en tarif réduit). Il n’y avait plus d’audioguides quand on y est allé, mais il restait des guides papiers (1€ en supplément, en français). Le guide papier est très bien fait et vous guidera à travers tout le (très vaste !) monastère. Compter au moins une bonne heure de visite pour bien profiter du lieu. C’est sûrement la visite la mieux guidée et détaillée qu’on a faite au Portugal. On traverse les multiples cloîtres, la rotonde de la chapelle est magnifique et la célèbre fenêtre de style manuélin est incroyable ! <a href="https://fr.wikipedia.org/wiki/Couvent_de_l%27ordre_du_Christ">Wikipédia</a> a une page assez complète avec photos aussi.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/DSC06394.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/DSC06394_mini.JPG" alt="La fenêtre manuéline" />
</a>
</p>
<p>Les ruelles dans la ville, au pied du couvent, sont très typiques. La <a href="https://www.openstreetmap.org/way/462190532">synagogue</a> est censée valoir le coup d’œil, mais elle était fermée pour travaux. L’église de <a href="https://www.openstreetmap.org/way/95600141">São João Baptista</a> (et la place devant) est très jolie, comme la plupart des églises du Portugal.</p>
<p>Pour goûter, on a testé (et approuvé !) le <a href="https://www.openstreetmap.org/node/2962419029">café Rialto</a>.</p>
<p>On reprend la route pour <a href="https://www.openstreetmap.org/relation/6461804">Fatima</a> où on a prévu de passer la nuit. En chemin, on s’arrête à l’<a href="https://www.openstreetmap.org/way/132277788">Aqueducto dos Pegões</a>, un aqueduc long de plusieurs kilomètres et qui amenait de l’eau au couvent (voir l’article <a href="https://fr.wikipedia.org/wiki/Aqueduc_des_Peg%C3%B5es">Wikipédia</a> aussi). On a une jolie vue sur la campagne autour et on sort un peu des grandes routes en plus :) On continue ensuite sur les petites routes jusqu’au <a href="https://www.openstreetmap.org/node/1069241520">chateau d’Ourem</a> (la nouvelle ville n’a que peu d’intérêt). Attention, les routes sont étroites et ça monte ! Il faut se garer devant <a href="https://www.openstreetmap.org/node/1069241445">l’église</a> (et hop, encore une jolie église !). On peut ensuite continuer à pied dans le vieux bourg au pied du château. Au château, on a un superbe panorama à 360° sur toute la région. L’accès est libre (et ouvert en permanence) mais le château est en partie en ruines (attention aux enfants ou si vous êtes sujet au vertige). Un très bon article sur la vieille ville d’Ourem est <a href="https://francoportugais.com/2008/10/vieille-ville-et-chateau-de-ourem/">ici</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/DSC06417.JPG">
<img style="max-width: 40%;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/DSC06417_mini.JPG" alt="L'aquedecuto dos Pegões" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/DSC06438.JPG">
<img style="max-width: 40%; margin-left: 1em;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/DSC06438_mini.JPG" alt="Le château d'Ourem" />
</a>
</p>
<p>Finalement, on arrive à Fatima où on va passer la soirée. Disons le tout de suite, Fatima n’a pas un grand intérêt (sauf si vous êtes très catholique et voulez voir la basilique). La plupart des bâtiments sont très récents, et tout a été construit après l’apparition de la Vierge au début du XXe siècle. Près de la basilique, on se promène entre les boutiques à touristes (vendant tous les objets pieux imaginables et plus encore). Le bon côté, c’est qu’en-dehors des pèlerinages (ouf, on y a échappé à 3 jours près cette fois-ci !), il n’y a pas grand monde et les hôtels sont très bon marché (par contre, pendant les célébrations, c’est l’horreur et noir de monde). On est resté à la <a href="https://www.openstreetmap.org/node/5664522958">Résidence S. Francisco</a>, un hôtel 3 étoiles qui nous a coûté 30€ la nuit. La chambre n’était pas très grande, mais très confortable et la salle de bains avait une baignoire, pour ce prix c’est imbattable ! On notera la vue sur la basilique, mais surtout l’icône de la Vierge encastrée dans le mur face au lit ! Si vous êtes de passage sans être particulièrement intéressé par les apparitions de la Vierge à Fatima, la <a href="https://www.openstreetmap.org/node/3636039152">basilique</a> est quand même jolie, l’esplanade devant est assez incroyable (et surtout d’imaginer qu’elle peut être remplie entièrement lors des grands pélerinages). La <a href="https://www.openstreetmap.org/node/3636039151">Basílica da Santíssima Trindade</a> en face a une architecture très moderne (un disque de 125m de diamètre, deux grandes poutres porteuses qui traversent l’édifice et soutiennent la toiture) et la statue du <a href="https://www.openstreetmap.org/node/3636039153#map=19/39.62938/-8.67468">Christ sur la croix</a> tranchent complètement avec le côté opposé de l’esplanade. C’est à peu près tout ce qu’il y a à voir à Fatima.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/DSC06450.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j4/DSC06450_mini.JPG" alt="La basilique à Fatima" />
</a>
</p>
<p>Pour manger le soir, on a trouvé <a href="https://www.openstreetmap.org/node/3695061890">Manhas</a>, un restaurant plutôt chic (mais pas trop cher, plats entre 10 et 15€, compter environ 20€ par personne pour plat + dessert) qui fait de la cuisine régionale (morue, poissons etc.). On a même réussi à avoir une carafe d’eau (voir plus bas pour les difficultés à avoir de l’eau du robinet au restaurant) !</p>
<h2>Mardi : Fatima - Batalha - Alcobaça - Nazaré (en voiture, 1h30 de route, 80km)</h2>
<p style="text-align: center">
<a href="https://maps.openrouteservice.org/directions?n1=39.610449&n2=-8.730011&n3=11&a=39.632281,-8.67104,39.672994,-8.833553,39.60347,-8.818833,39.551768,-8.975239,39.601687,-8.955317,39.603922,-9.066316&b=0&l6=1&c=0&k1=fr-FR&k2=km">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/j5.png"
alt="Trajet le mardi" />
</a>
</p>
<p>Le trajet est visible
<a href="https://maps.openrouteservice.org/directions?n1=39.610449&n2=-8.730011&n3=11&a=39.632281,-8.67104,39.672994,-8.833553,39.60347,-8.818833,39.551768,-8.975239,39.601687,-8.955317,39.603922,-9.066316&b=0&l6=1&c=0&k1=fr-FR&k2=km">ici</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06467.JPG">
<img style="max-width: 25%;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06467_mini.JPG" alt="Entrée du monastère de Batalha" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06469.JPG">
<img style="max-width: 25%; margin-left: 1em;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06469_mini.JPG" alt="Forêt de piliers dans l'église du monastère de Batalha" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06481.JPG">
<img style="max-width: 25%; margin-left: 1em;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06481_mini.JPG" alt="Monastère de Batalha" />
</a>
</p>
<p>Le lendemain matin, départ pour <a href="https://www.openstreetmap.org/relation/5399199">Batalha</a>, ville qui abrite <a href="https://www.openstreetmap.org/way/444670165">le deuxième des monastères</a> du coin classés au patrimoine mondial de l’<span class="caps">UNESCO</span> (cf le billet combiné disponible à Tomar). La ville s’est construite autour du monastère, et il n’y a pas grand chose d’autre à voir en fait. L’entrée dans l’église est gratuite, mais la visite du monastère en lui-même est payante. Il n’y avait pas d’audioguide, mais un guide imprimé en papier disponible pour 1€ (comme à Tomar, bien qu’un peu moins complet que ce dernier). La visite commence par l’église (gratuite) puis les deux cloîtres (après le contrôle des billets) et les salles attenantes (salle du chapitre, cuisines, etc.). On ressort ensuite pour aller voir les <a href="https://www.openstreetmap.org/way/444670163#map=19/39.65928/-8.82571">Chapelles Imparfaites</a> (après un autre contrôle des billets mais pas de supplément à payer) qui sont un ensemble de chapelles inachevées destinée à être le panthéon de Dom Duarte et l’ultime demeure des rois portugais. Beaucoup d’informations sur le monastère sont disponibles sur <a href="https://vicedi.com/monastere-batalha/">cette page</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06490.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06490_mini.JPG" alt="Les chapelles imparfaites" />
</a>
</p>
<p>Le midi, on est allé manger au <a href="https://www.openstreetmap.org/node/5667063572">Café O Ligeiro</a>, un peu en retrait de la zone touristique autour du monastère. C’est un peu comme une cantine, chaque jour on peut choisir entre deux ou trois plats simples déjà préparés. Ce jour, il y avait du hachis parmentier (et salade + crudités) ou de la viande grillée. Les portions sont assez généreuses et les plats sont bons. Les desserts étaient top aussi, avec de la salade de fruits frais. La clientèle est essentiellement composée d’habitants du quartier. Compter moins de 10€ par personne pour un plat, un dessert, boisson et café.</p>
<p>L’après-midi, direction <a href="https://www.openstreetmap.org/relation/5399253#map=14/39.5524/-8.9630">Alcobaça</a>, <a href="https://www.openstreetmap.org/relation/6188779">le dernier des trois monastères</a> inscrit au patrimoine mondial de l’<span class="caps">UNESCO</span> (cf le billet combiné à Tomar). Avant d’arriver à Alcobaça, on fait un arrêt à <a href="https://www.openstreetmap.org/relation/6548216">Porto de Mos</a> et en particulier au <a href="https://www.openstreetmap.org/way/145457353">château</a> qui offre un magnifique point de vue sur le <a href="https://fr.wikipedia.org/wiki/Parc_naturel_des_Serras_de_Aire_et_Candeeiros">parc naturel des Serras de Aire et Candeeiros</a>. On peut se garer proche du château (ça monte nettement moins qu’à Ourem). On peut <a href="http://www.municipio-portodemos.pt/Page.aspx?id=162">visiter le château</a> (environ 1.5€ par personne), mais il était fermé quand on y est passé :( Une fois arrivé à Alcobaça, on a trouvé à se garer sur le <a href="https://www.openstreetmap.org/way/119965898">grand parking</a> (gratuit) à proximité du monastère. Beaucoup de détails et de photos du monastère sont disponibles <a href="https://vicedi.com/monastere-alcobaca/">ici</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06520.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06520_mini.JPG" alt="Le monastère d'Alcobaça" />
</a>
</p>
<p>Comme à Batalha, l’entrée dans l’église du monastère d’Alcobaça est gratuite et il y a un contrôle des billets pour visiter les cloîtres. Il y a aussi un guide papier en français (assez complet) disponible pour 1€. Il est possible de visiter la sacristie et <a href="https://www.openstreetmap.org/way/415374532">la chapelle de l’exil</a> mais il faut payer 2€ en plus et réserver en avance apparemment.</p>
<p>Pour goûter, on a testé la <a href="https://www.openstreetmap.org/node/4700162390">Pastelaria Alcoa</a>, une pâtisserie qui propose un large éventail de pâtisseries typiques portugaises et qui a remporté de nombreux prix portugais. Pas particulièrement plus cher qu’ailleurs, et très bon (et toujours avec beaucoup de jaune d’œuf !) :) Les rues du centre ville, derrière la pâtisserie, et les chemins le long des deux rivières, l’Alcoa et la Baça (d’où la ville tire son nom), et vers le <a href="https://www.openstreetmap.org/way/278570753">Jardin de l’amour</a> sont très agréables aussi pour se promener.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06513.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06513_mini.JPG" alt="Les pâtisseries chez Alcoa" />
</a>
</p>
<p>En reprenant la route pour Nazaré, on s’est arrêté un peu par hasard au <a href="https://www.openstreetmap.org/way/459882254">Convento de Santa Maria de Coz</a>, un ancien couvent perdu dans la campagne. Il est un peu en dehors des sentiers touristiques (il n’y avait strictement personne quand on est arrivé), mais à ne surtout pas rater, c’est magnifique ! Il y a deux parties au couvent. La partie <a href="https://www.openstreetmap.org/way/517438196">la plus ancienne</a> est essentiellement en ruines et en accès libre. Ce n’est pas non plus la plus intéressante. Pour accéder au couvent, il faut aller demander au <a href="https://www.openstreetmap.org/node/5026973287">magasin d’artisanat</a> à proximité. La visite est assez courte (3 salles en tout, environ 15 minutes) mais gratuite et guidée par le gardien (fonctionnement au pourboire mais il n’est absolument pas insistant). L’intérieur est couvert d’<em>azulejos</em> et de boiseries et tout simplement magnifique. <a href="https://www.openstreetmap.org/node/5026973287">Coz’Arte</a> (le magasin d’artisanat religieux) vend des objets à base d’osier et les artisans sont adorables et nous ont même fait tresser de l’osier !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06528.JPG">
<img style="max-width: 40%; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06528_mini.JPG" alt="Le convento de Santa Maria de Coz" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06531.JPG">
<img style="max-width: 40%; margin-left: 1em; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06531_mini.JPG" alt="Le convento de Santa Maria de Coz" />
</a>
</p>
<p>On reprend finalement la route en direction de <a href="https://www.openstreetmap.org/node/25278374">Nazaré</a>, un petit port de pêche sur la côte et notre dernière étape de la journée. On a passé la nuit chez <a href="https://www.booking.com/hotel/pt/tiagorge-place.fr.html">Tiago <span class="amp">&</span> Jorge Guest House</a> (<a href="https://www.openstreetmap.org/changeset/59582044">ici</a> sur la carte), une chambre d’hôte très propre, confortable, en plein centre ville et d’un excellent rapport qualité / prix (environ 25€ / nuit). Les chambres ont une salle de bain privée et il y a une cuisine commune.</p>
<p>Attention, à Nazaré, il est très difficile de se garer dans la partie basse de la ville (le long de la plage). Vous pourrez peut être vous garer (gratuitement ?) devant votre hébergement (ça a été notre cas, mais il n’y avait pas grand monde dans la chambre d’hôte), mais les rues sont assez étroites. Il y a un peu de stationnement avec des parcmètres en ville payant en journée uniquement, mais limité à 3h. La durée limite n’est pas très claire mais le parcmètre ne nous laissait pas mettre de l’argent correspondant à 2h le soir et 1h le matin. Enfin, il y a <a href="https://www.openstreetmap.org/way/152066444">un grand parking</a> sur plusieurs étages (mais assez ouvert) au même prix que le parcmètre, mais toutes les heures sont payantes et non uniquement durant la journée. Sinon, la meilleure option semble être d’aller se garer vers <a href="https://www.openstreetmap.org/node/2946311323#map=16/39.6046/-9.0733">le Sitio</a> (voir plus bas), mais il faut alors marcher (et ça monte !).</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06578.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06578_mini.JPG" alt="Nazaré, vue depuis le Sitio" />
</a>
</p>
<p>L’essentiel à voir dans la partie basse de la ville (outre la très grande plage) se situe au pied du <a href="https://www.openstreetmap.org/node/1647989387">funiculaire</a> et autour de la <a href="https://www.openstreetmap.org/way/152066444">Praça Sousa Oliveira</a> ainsi que le <a href="https://www.openstreetmap.org/node/1648957984">marché municipal</a> (et en particulier les stands avec le poisson mis à sécher !). Le quartier du <a href="https://www.openstreetmap.org/node/2946311323#map=16/39.6046/-9.0733">Sitio</a> est très intéressant aussi. On y accède depuis la partie basse soit avec le funiculaire, soit en suivant <a href="https://www.openstreetmap.org/way/414834058">les escaliers</a> (attention, ça monte !). En haut, on peut profiter d’une <a href="https://www.openstreetmap.org/node/4130550675">superbe vue sur la ville</a> et visiter le <a href="https://www.openstreetmap.org/relation/6160640">Santuário de Nossa Senhora da Nazaré</a>, une jolie église du 14e siècle, avec comme toujours, des <em>azulejos</em> :) Sur la place de l’église, au bord de la falaise, ne pas manquer la toute petite <a href="https://www.openstreetmap.org/way/151964427">chapelle de la mémoire</a>. Selon la légende, un templier chassait un cerf par une matinée brumeuse de 1182 quand il vit le cerf tomber brusquement, au bord de la falaise. Il aurait invoqué l’aide de la Vierge qui aurait stoppé net son cheval, à temps. La chapelle de la mémoire serait construire à l’endroit où son cheval s’est arrêté. Les plus courageux pourront suivre la route jusqu’au <a href="https://www.openstreetmap.org/node/1647978358">Farol da Nazaré</a>, à l’extrémité de la pointe (environ 10 minutes de marche) pour profiter de la vue sur la ville et sur les grandes plages au Nord (on va au Farol uniquement pour la vue, il ne se visite pas). Enfin, un dernier point de vue sur la ville et le port se trouve <a href="https://www.openstreetmap.org/node/5600018321">sur la colline en face</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06581.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j5/DSC06581_mini.JPG" alt="La chapelle de la mémoire" />
</a>
</p>
<p>Le soir, on a mangé chez <a href="https://www.openstreetmap.org/node/5669717674">Maria Do Mar</a>, un très bon restaurant de poissons et fruits de mer dans le vieux Nazaré. Déco assez chargée, beaucoup de bibelots, c’est assez rigolo. Compter 10-15€ pour un plat. On a testé (et on recommande !) la <a href="https://fr.wikipedia.org/wiki/Caldeirada">caldeirada</a>, assez proche de la bouillabaisse. Les portions servies sont très très généreuses.</p>
<h2>Mercredi : Nazaré - Obidos - Peniche (en voiture, 1h45 de route, 80km)</h2>
<p style="text-align: center">
<a href="https://maps.openrouteservice.org/directions?n1=39.399857&n2=-9.337349&n3=11&a=39.603922,-9.066316,39.43268,-9.227228,39.40682,-9.191437,39.40381,-9.133536,39.364587,-9.14997,39.359752,-9.156128,39.371107,-9.336984,39.364829,-9.404812,39.354144,-9.380522&b=0&l6=1&c=0&k1=fr-FR&k2=km">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/j6.png"
alt="Trajet le mercredi" />
</a>
</p>
<p>Le trajet est visible
<a href="https://maps.openrouteservice.org/directions?n1=39.399857&n2=-9.337349&n3=11&a=39.603922,-9.066316,39.43268,-9.227228,39.40682,-9.191437,39.40381,-9.133536,39.364587,-9.14997,39.359752,-9.156128,39.371107,-9.336984,39.364829,-9.404812,39.354144,-9.380522&b=0&l6=1&c=0&k1=fr-FR&k2=km">ici</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06608.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06608_mini.JPG" alt="La lagune d'Obidos" />
</a>
</p>
<p>Au programme de ce jour : <a href="https://www.openstreetmap.org/node/2620015278#map=13/39.3894/-9.1350">Obidos</a> (et sa lagune), une ville fortifiée, puis <a href="https://www.openstreetmap.org/node/25278379">Peniche</a>, un petit port de pêche sur la côte. En direction d’Obidos, on passe à <a href="https://www.openstreetmap.org/node/5163116401">Foz de Arelho</a>, au bout de la lagune. De là, on a une magnifique vue sur la plage sur l’océan (et ses grosses vagues et surfeurs) et la lagune, abritée. La route le long de la lagune jusqu’à <a href="https://www.openstreetmap.org/node/5163116401">Nadadouro</a> est très sympa.</p>
<p>En chemin pour Obidos, on a voulu s’arrêter à <a href="https://www.openstreetmap.org/node/2905742464">Caldas da Rainha</a> qui est une station thermale également célèbre pour ses céramiques (plus d’infos par <a href="https://www.augoutdemma.be/46728-caldas-da-rainha-etape-surprenante-dans-le-centre-du-portugal">ici</a>). Ce fut un échec total… L’essentiel du centre ville est piéton et la circulation en voiture à proximité est assez horrible (globalement, tout le centre ville était bouché), surtout un jour de marché ! Du coup, on n’a pas réussi à se garer et on a continué notre route. Si vous êtes plus chanceux que nous, un bon point de départ semble être la <a href="https://www.openstreetmap.org/way/490739751">Praça da Republica</a> (qui est aussi la place du marché).</p>
<p>Juste avant d’arriver à Obidos, ne ratez pas l’église <a href="https://www.openstreetmap.org/way/298272106">Senhor Jesus da Pedra</a>, une surprenante église baroque ! L’extérieur de l’église est circulaire mais le plan intérieur est hexagonal !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06635.JPG">
<img style="max-width: 40%; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06635_mini.JPG" alt="Les toits d'Obidos" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06629.JPG">
<img style="max-width: 40%; margin-left: 1em; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06629_mini.JPG" alt="Le château d'Obidos" />
</a>
</p>
<p>Vous ne pourrez pas rentrer dans l’enceinte fortifiée en voiture mais il y a pas mal de parkings devant les remparts. Il y a plusieurs parkings le long de la <span class="caps">EN</span> 8, attention certains sont payants et d’autres sont gratuits (alors qu’ils sont distants de quelques mètres)… En entrant dans la ville fortifiée, ne pas rater les <em>azulejos</em> dans la <a href="https://www.openstreetmap.org/node/4698259991">porte de la ville</a>. En entrant, la rue en face est la rue principale, le long de laquelle il y a la plupart des commerces (et des boutiques de <em>ginjinha</em>, la liqueur de cerises griottes locale servie dans un verre en chocolat). Juste avant d’arriver sur la praça de Santa Maria, il y a le petit <a href="https://www.openstreetmap.org/way/299063768">musée municipal</a> sur la droite (3 salles, entrée gratuite). L’<a href="https://www.openstreetmap.org/way/147555812">Igreja de Santa Maria</a> est une jolie église avec (toujours) des <em>azulejos</em>. Finalement, au bout de la rue Direita, ne manquez pas l’étonnante <a href="https://www.openstreetmap.org/way/298856006">Livraria de São Tiago </a>, dans une ancienne église. Le <a href="https://www.openstreetmap.org/way/64880896">château</a> offre un joli point de vue sur les toits rouges de la ville et la campagne autour. Tout le tour des remparts peut se faire <a href="https://www.openstreetmap.org/way/475653565#map=17/39.36158/-9.15792">à pied</a> (les accès sont assez larges et sécurisés, attention aux enfants et aux personnes souffrant de vertige, il n’y a pas de parapet intérieur, du côté de la ville). N’hésitez pas à vous écartez un peu de la rue Direita et prendre des rues transverses, nettement moins fréquentées et plus agréables !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06620.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06620_mini.JPG" alt="Une bien étrange librairie !" />
</a>
</p>
<p>Le midi, on a pris des sandwiches au <a href="https://www.openstreetmap.org/node/2588836772">Café O Tubas</a>. La carte n’était absolument pas claire, mais il y avait pas mal de sandwich (format “club sandwich”, pas très gros, autour de 2€). Pratique et pas trop cher, mais pas forcément le meilleur plan du coin…</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06640.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06640_mini.JPG" alt="La presqu'île de Baleal" />
</a>
</p>
<p>En chemin pour Peniche, on s’est arrêté un peu par hasard à <a href="https://www.openstreetmap.org/node/1676909915#map=15/39.3730/-9.3367">Baleal</a>, un étonnant village sur une presqu’île reliée par une langue de sable à la terre. L’idéal est de se garer au <a href="https://www.openstreetmap.org/way/138697559">parking</a> (gratuit) sur le continent, puis de traverser la bande de sable à pied et d’aller faire un tour dans le village. Il y a un joli panorama sur les plages alentour (paradis des surfeurs) et la presqu’île de Peniche. Étonnament, les cafés en bord de plage ne sont pas particulièrement plus chers qu’ailleurs !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06664.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06664_mini.JPG" alt="Autour de la presqu'île de Peniche" />
</a>
</p>
<p>Arrivé à Peniche, le tour de la presqu’île par la <span class="caps">EN</span>-114 est super, avec de nombreux points de vue et des paysages assez changeants en l’espace de quelques kilomètres (falaises abruptes, rochers plus doux etc.). Peniche est un petit village au bord de la mer et un port de pêche. Le centre ville est assez authentique. La <a href="https://www.openstreetmap.org/node/4128477516">forteresse</a> est malheureusement fermée pour travaux en ce moment. Il y a pas mal de conserveries à côté du port, mais rien qui a l’air de se visiter (comme la Belle-Iloise). L’autre spécialité de la ville, c’est la <em>renda</em>, un ensemble de technique de broderie. Il y a un <a href="https://www.openstreetmap.org/node/5670603988">musée</a> en ville, plutôt bien fait et gratuit, qui présente la <em>renda</em> et les techniques.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06667.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06667_mini.JPG" alt="La forteresse de Peniche" />
</a>
</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06697.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06697_mini.JPG" alt="Encore une église richement décorée !" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06699.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j6/DSC06699_mini.JPG" alt="Une petite rue de Peniche" />
</a>
</p>
<p>Le soir, on a logé à <a href="https://www.booking.com/hotel/pt/o-forte-guest-house.pt-pt.html">O Forte Guesthouse</a>, une immense chambre d’hôte située juste en face de la forteresse. Excellent rapport qualité/prix (36€ la nuit), il y a 6 ou 7 chambres dans une grande maison, avec cuisine et salon commun. Très propre (il n’y avait que deux chambres occupées cependant), 2 grandes salles de bain pour 6 chambres. Il y a un <a href="https://www.openstreetmap.org/way/138705617">grand parking gratuit</a> devant la maison. Pour sortir le soir, les plages sont fréquentées par les surfeurs et il y a donc tout ce qu’il faut. Les restaurants au bord du port avaient plutôt l’air d’être dans la catégorie « touristique et plutôt cher pour ce que c’est », donc on n’a pas testé et on a mangé dans la chambre d’hôte.</p>
<h2>Jeudi : Peniche - Sintra - Cabo da Roca - Cascais / Estoril - Lisbonne (en voiture, 2h45 de route, 160km)</h2>
<p style="text-align: center">
<a href="https://maps.openrouteservice.org/directions?n1=38.991971&n2=-8.844681&n3=10&a=39.354144,-9.380522,38.802225,-9.376527,38.787464,-9.390537,38.778242,-9.430046,38.770179,-9.458027,38.781854,-9.497236,38.691052,-9.430619,38.727736,-9.13487&b=0&l6=1&c=0&k1=fr-FR&k2=km">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/j7.png"
alt="Trajet le jeudi" />
</a>
</p>
<p>Le trajet est visible <a href="https://maps.openrouteservice.org/directions?n1=38.991971&n2=-8.844681&n3=10&a=39.354144,-9.380522,38.802225,-9.376527,38.787464,-9.390537,38.778242,-9.430046,38.770179,-9.458027,38.781854,-9.497236,38.691052,-9.430619,38.727736,-9.13487&b=0&l6=1&c=0&k1=fr-FR&k2=km">ici</a>.</p>
<p>Au programme de ce jour, départ assez tôt pour être assez tôt à <a href="https://www.openstreetmap.org/relation/6528470">Sintra</a> (avant l’afflux de touristes), célèbre pour ses palais, puis passage à <a href="https://www.openstreetmap.org/node/376079140">Cabo da Roca</a>, le point le plus à l’ouest du continent européen, avant de rejoindre Lisbonne.</p>
<p>Se garer à Sintra peut être un peu compliqué. Le plus simple est probablement de se garer sur <a href="https://www.openstreetmap.org/way/565790512">le parking devant la gare de Portela</a> (1.8€ / 24h) puis d’aller dans le centre à pied (il semblerait également que le parking de l’autre côté de la route soit gratuit). Le stationnement dans Portela de Sintra se fait essentiellement au parcmètre et est très compliqué et très cher. L’autre possibilité est de se rapprocher du centre de Sintra, il y a <a href="https://www.openstreetmap.org/way/565792253">des parcmètres</a> le long de la route. Ce n’était pas plus cher et les touristes ne doivent pas oser aller jusque là et il y avait des places libres.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06700.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06700_mini.JPG" alt="Le palais national de Sintra" />
</a>
</p>
<p>Le matin, on commence par visiter le <a href="https://www.openstreetmap.org/relation/1633002">Palais national de Sintra</a> (10€ en tarif adulte, quelques pourcents de réduction si vous prenez un billet combiné avec un autre site). Vous pouvez prendre vos billets en avance <a href="https://www.parquesdesintra.pt/planear-a-sua-visita/horarios-e-precos/">en ligne</a>, ce qui permet d’éviter la queue à la billetterie. Les dépliants avec des explications sur la visite sont à la billetterie néanmoins, et il faudra réussir à vous faufiler pour en récupérer un (gratuit, plutôt complet, similaire à ceux des monastères). Il y a aussi des audioguides payants. Compter une heure de visite.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06716.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06716_mini.JPG" alt="La Quinta da Regaleira" />
</a>
</p>
<p>Pas très loin, le long de la route, vous trouverez la <a href="https://www.openstreetmap.org/way/169844121#map=19/38.79609/-9.39138">Quinta da Regaleira</a>. L’entrée est à 6€ et on avait déjà un programme un peu chargé pour la journée, donc je ne peux pas vous en dire beaucoup plus :) Dans Sintra, il y a la <a href="https://www.openstreetmap.org/node/1831390490">Pâtisserie Piriquita</a>, qui fait des spécialités de la ville : les <a href="http://a-la-decouverte-et-redecouverte-du-portugal-2013.over-blog.com/2013/11/59-le-travesseiro-de-sintra.html"><em>travesseiros</em></a> (pâte feuilletée et amandes) et les <a href="http://porthelio.blogspot.com/2014/08/les-queijadas-de-sintra.html"><em>queijadas</em></a> (sorte de <em>cheese cake</em>). Par contre, la pâtisserie est plutôt chère par rapport aux autres pâtisseries qu’on a eu l’occasion de voir pendant notre séjour.</p>
<p>Le midi, on a mangé à <a href="https://www.openstreetmap.org/node/5672932624">A Pendoa</a>, une petite boutique de souvenirs qui fait aussi restaurant. Cuisine typique (bacalhau, poisson grillé, salades etc.), compter 10-15€ par personne (plats à 5-10€).</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06760.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06760_mini.JPG" alt="Le palais de Pena, il n'y a plus qu'à monter ! :)" />
</a>
</p>
<p>L’après-midi, on a repris la voiture pour visiter le <a href="https://www.openstreetmap.org/way/455683568#map=16/38.7855/-9.3923">Palais de Pena</a>. La route d’accès en voiture est assez sinueuse (mais les bus la prennent, alors c’est faisable !), mais heureusement elle est à sens unique. Il y a plusieurs entrées au parc et il faut donc se garer quand on peut et rejoindre l’entrée la plus proche. Une autre possibilité est de monter à pied depuis le centre ville de Sintra (il y a un chemin de randonnée, environ 3km jusqu’au palais, compter une heure en montée). On a réussi à se garer à côté de l’entrée <a href="https://www.openstreetmap.org/node/1860911898#map=16/38.7877/-9.3935"><em>Vale dos lagos</em></a>. Ne pas oublier de récupérer un dépliant explicatif (comme toujours, celui-ci est gratuit) à <a href="https://www.openstreetmap.org/way/170024787">la billetterie</a>. Les billets sont à 14€ pour le parc et le palais (le plus intéressant) et 8€ pour le parc seulement. Si vous ne voulez pas ou ne pouvez pas monter au palais en traversant le parc à pied (compter 20 bonnes minutes de montée), il y a un minibus dans le parc pour 2€. Compter une bonne heure de visite dans le château. Si vous voulez profiter un peu du parc sans être pressé, compter bien 3h à passer sur le site. Les plus courageux iront jusqu’à la <a href="https://www.openstreetmap.org/node/3906378865">Cruz Alta</a> (compter 20 bonnes minutes de marche depuis le palais) qui est le point le plus haut du parc, offrant un superbe point de vue sur la région et le palais.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06748.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06748_mini.JPG" alt="La cruz alta du palais de Pena" />
</a>
</p>
<p><a href="https://wikitravel.org/en/Sintra">Wikitravel</a> a un bon aperçu des endroits touristiques à proximité de Sintra (nombreuses <em>quintas</em>, le château des Maures etc.). Le palais national et le palais de Pena remplissaient déjà bien la journée, il faudra y retourner !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06777.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06777_mini.JPG" alt="Vue sur la côte depuis le sanctuaire de Peninha" />
</a>
</p>
<p>On a ensuite repris la route pour <a href="https://www.openstreetmap.org/way/184073572">Cabo da Roca</a>, le point le plus à l’ouest du continent européen. Attention, les routes qui traversent le parc naturel de Sintra-Cascais, en direction de Cabo da Roca sont de petites routes assez sinueuses. Pas très gênant, et vous ne croiserez pas grand monde, mais pas le plus rapide non plus. Aussi, on n’a vu aucune station essence sur notre chemin entre Sintra et Cascais. En chemin, on s’est arrêté au <a href="https://www.openstreetmap.org/node/5618046218">sanctuaire de Peninha</a>, où après une courte ascension (5 minutes) on a un super panorama sur toute la région, Cabo da Roca et Cascais. Finalement, on arrive à Cabo da Roca, où on peut faire la photo de touriste devant le panneau “Point le plus à l’ouest du continent” !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06789.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06789_mini.JPG" alt="Cabo da Roca" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06794.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06794_mini.JPG" alt="Cabo da Roca" />
</a>
</p>
<p>En repartant à Lisbonne, on s’est arrêté rapidement à la <a href="https://www.openstreetmap.org/node/1605525948#map=16/38.6920/-9.4305">Boca do Inferno</a>, un pont suspendu créé par la mer qui a attaqué une falaise. Deux possibilités pour rentrer à Lisbonne : prendre l’autoroute (direct et plus rapide), ou longer la côte par Cascais et Estoril (le casino d’Estoril <a href="https://www.augoutdemma.be/36790-cascais-et-la-riviera-portugaise-sur-les-traces-de-james-bond">aurait servi de base</a> à l’histoire du James Bond Casino Royale). On est un peu en retard pour rendre la voiture le soir même et Cascais et Estoril sont des stations balnéaires assez bétonnées, donc on opte pour l’autoroute. Une petite altercation avec l’agence Sixt où on rend la voiture (voir plus bas) plus tard, direction notre Airbnb pour tout notre séjour à Lisbonne, chez <a href="https://www.airbnb.fr/rooms/24318357">Jesus</a> (très bien situé et très bon rapport qualité / prix, un peu petit pour 2 personnes par contre). Comme toujours, on n’a pas prévu plus que ça et on découvre en arrivant que l’Eurovision se passe deux jours plus tard à Lisbonne. Cela explique probablement pourquoi aucun hébergement n’était disponible… Le soir, on a mangé chez <a href="https://www.openstreetmap.org/node/5653851095">Solar Minhoto</a>, notre nouveau <span class="caps">QG</span> à proximité du Airbnb. Compter 15€ par personne pour plat, dessert et boisson le soir. Les plats changent chaque jour (deux plats par jours, un poisson frais et une viande). Les desserts sont top ! :)</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06813.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j7/DSC06813_mini.JPG" alt="Boca do Inferno" />
</a>
</p>
<p>Note sur les trajets : On a tout fait en voiture car on ne savait pas vraiment comment faire autrement et qu’on avait de toutes façons la voiture. Si vous venez de Lisbonne, il est probablement plus simple de tout faire en transports en commun, ce qui évite de s’inquiéter de garer la voiture (surtout en saison touristique). Depuis Lisbonne, le train vous dépose à <a href="https://www.openstreetmap.org/node/1146426351">Sintra</a> qui est très près du centre ville de Sintra. Vous pourrez rejoindre le palais national et la quinta da Regaleira à pied (ou prendre le bus 435) facilement. Scotturb (le service de bus publics de Sintra - Cascais) propose ensuite <a href="http://scotturb.com/pt/carreiras/tarifario/turisticos-2018">des billets</a> pour le circuit de Pena (bus 434 qui relie le centre de Sintra au palais de Pena et au château des Maures) ou des billets journée valable sur tout le réseau. Le bus 403 relie Sintra à Cascais en s’arrêtant à Cabo da Roca. Et depuis Cascais, vous pourrez reprendre le train pour Lisbonne. Le seul élément de la journée que vous ne pourrez pas voir sans voiture est le sanctuaire de Peninha.</p>
<h2>Vendredi : Lisbonne côté est (à pied et transports publics)</h2>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06837.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06837_mini.JPG" alt="Vue sur Lisbonne depuis le point de vue de Nossa Senhora do Monte" />
</a>
</p>
<p>Premier jour à Lisbonne, on en profite pour faire un gros tour de la ville. On a fait l’essentiel de la journée à pied (retour en métro uniquement), mais ça fait pas mal de marche dans la journée et Lisbonne n’est pas une ville plate du tout ! Pour prendre les transports en commun, comme à Porto, il faut commencer par acheter une carte rechargeable (50 centimes, non remboursable). Vous pourrez ensuite :</p>
<ul>
<li>soit charger des titres de transport individuels dessus, pour des déplacements ponctuels</li>
<li>soit fonctionner en mode “Zapping”. Au lieu de charger des titres de transports, vous chargerez un montant fixé. Votre carte rechargeable devient un porte-monnaie virtuel et l’argent sera pris dessus à chaque passage. C’est le plus rentable pour faire quelques trajets par jour, mais attention, vous ne pouvez recharger que des montants prédéfinis (3€, 5€ etc.) et aucun remboursement de l’argent restant sur la carte n’est possible !</li>
<li>soit charger un billet 24h (voyages illimités pendant 24h sur le réseau de transport : bus, tramways, métros et certains funiculaires). Un ticket 24h coûte environ 6€ (environ 9€ pour avoir les traversées en ferry en illimité en plus). À noter : le billet est valable <strong>24h</strong> (et non une journée). Si vous chargez tous les billets au début de votre séjour, ils s’enchaîneront. Il vaut en général mieux les charger au fur et à mesure de vos besoins, ce qui permet de gagner en moyenne un billet sur quelques jours. Par exemple, vous chargez votre premier billet 24h à 10h le premier jour. À 10h le lendemain, il arrive à expiration, mais vous allez sûrement visiter des musées et vous balader à pied et ne pas prendre le métro avant 17h. En rechargeant un autre billet à 17h, vous avez donc gagné 7h.</li>
</ul>
<p>Attention, quel que soit le mode de fonctionnement choisi, vous ne pourrez pas changer de fonctionnement tant que la carte ne sera pas vidée. Par exemple, si vous avez un billet 24h sans les ferrys et voulez prendre un billet pour les ferrys, il faudra racheter une carte rechargeable en plus du ticket de ferry. Les billets 24h sont particulièrement rentables les jours où vous prévoyez beaucoup de déplacements (prendre les funiculaires ou le tram, aller à Bélem etc.). Le funiculaire de Bica tout seul coûte 3€ mais est inclus dans le billet 24h par exemple. Tous les chargements peuvent se faire aux machines des stations de métro (peut-être ailleurs aussi, mais on n’a pas trouvé). À noter : les stations de métro sont assez irrégulièrement espacées et il n’y en a pas dans le Bairro Alto par exemple, il faut donc prévoir un minimum. Toutes les informations sur les transports à Lisbonne sont bien récapitulées dans <a href="http://www.visiterlisbonne.com/transports">cet article</a>.</p>
<p>Premier arrêt de la journée au point de vue de <a href="https://www.openstreetmap.org/way/526129020">Nossa Senhora do Monte</a> pour profiter du panorama à 360° sur la ville et le Tage. On continue ensuite en suivant la <a href="https://www.openstreetmap.org/way/24279356#map=17/38.71908/-9.13037">Rua da Graça</a> jusqu’au <a href="https://www.openstreetmap.org/way/45831368">Largo da Graça</a> et ses scènes de vie assez authentiques. À proximité, ne pas rater les cités ouvrières, notamment la très belle <a href="https://www.openstreetmap.org/relation/3314804">Villa Sousa</a> et sa façade en céramique bleue ainsi que la <a href="https://www.openstreetmap.org/way/104595598">Vila Berta</a>, un peu à l’écart et au calme. Il y a un autre <a href="https://www.openstreetmap.org/way/84256590">point de vue</a> devant l’<a href="https://www.openstreetmap.org/way/246085829">église de Graça</a> (encore une jolie église).</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06858.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06858_mini.JPG" alt="São Vicente de Fora" />
</a>
</p>
<p>On est ensuite descendu en direction du <a href="https://www.openstreetmap.org/node/5068486973">musée de São Vicente de Fora</a>. La visite de l’église adjacente est libre et gratuite. Le musée vaut vraiment le coup (entrée à 5€, tarif réduit à 2€50). On commence la visite par voir la citerne d’eau de l’ancien monastère, puis on parcourt des salles et des cloîtes couverts d’<em>azulejos</em> et une petite collection d’orfèvrerie religieuse. Le plus intéressant et amusant est une collection d’une vingtaine de panneaux d’<em>azulejos</em> illustrant des fables de La Fontaine, vraiment super ! On accède enfin à la terrasse de l’église (ça monte !) qui offre une vue superbe à 360° sur Baixa, l’Alfama et le Tage !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06876_BW.JPG">
<img style="max-width: 40%;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06876_BW_mini.JPG" alt="Des tombeaux…" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06886.JPG">
<img style="max-width: 40%; margin-left: 1em;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06886_mini.JPG" alt="Et des azulejos de fables de La Fontaine !" />
</a>
</p>
<p>Le midi, on est allé manger chez <a href="https://www.openstreetmap.org/node/5676101680">O Cantinho</a>. Plats pour 5-10€ mais attention ils ne prennent pas la carte bleue. On s’est arrêté rapidement mais il y avait l’air d’y avoir des restaurants plus intéressants à côté, qu’on a vu trop tard.</p>
<p>Après manger, en route pour voir le <a href="https://www.openstreetmap.org/node/4968085324">Castelo de S. Jorge</a>. L’entrée est à 8.5€ (5€ en tarif réduit). Je crois qu’il y a essentiellement des vestiges et le point de vue sur la ville. Comme il y avait une queue monstre et qu’on avait déjà été aux autres points de vue, on n’est pas rentré dans l’enceinte.</p>
<p>L’après-midi, on s’est promené dans <a href="https://www.openstreetmap.org/way/394631209">Baixa</a>, le quartier plat au bord du Tage qui a été reconstruit selon une grille après avoir été détruit par le tremblement de terre de 1755. C’est un peu comme l’hyper centre de Paris, avec de beaux bâtiments mais clairement pas l’endroit le plus accessible pour manger ou boire un verre :) Ne pas rater :</p>
<ul>
<li>la <a href="https://www.openstreetmap.org/way/96896573">Place du commerce</a> au Sud, le long du Tage, après l’<a href="https://www.openstreetmap.org/node/5457844732">arc de triomphe</a>.</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06927.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06927_mini.JPG" alt="L'arc de triomphe sur la Place du commerce" />
</a>
</p>
<ul>
<li>la <a href="https://www.openstreetmap.org/way/96770748">Praça da Figueira</a> au Nord, ainsi que sa voisine, la <a href="https://www.openstreetmap.org/way/96770751">Praça Dom Pedro <span class="caps">IV</span></a> (aussi appelée Rossio). Cette dernière a toujours été au cœur de la vie lisboète, et c’est sur cette place que le 25 avril 1974 un fleuriste aurait offert un bouquet d’œillets à un soldat insurgé contre la dictature de Salazar, commençant ainsi la Révolution des Œillets. Au Nord du Rossio, il y a le <a href="https://www.openstreetmap.org/way/77473968">théâtre national</a> et la <a href="https://www.openstreetmap.org/way/96530649#map=18/38.71467/-9.14194">gare du Rossio</a> (datant de 1890 mais avec une jolie façade de style manuélin).</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06903.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06903_mini.JPG" alt="La gare du Rossio" />
</a>
</p>
<ul>
<li>un peu plus au Nord, ne pas rater l’<a href="https://www.openstreetmap.org/way/95408993#map=19/38.71474/-9.13824">église de São Domingos</a>, une église assez sombre et aux murs marqués par les épreuves qu’elle a traversées. Elle a survécu au tremblement de terre de 1531, puis fut pratiquement détruite par le tremblement de terre de 1755. Reconstruite en 1807, elle a été dévastée par un incendie en 1959.</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06900.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06900_mini.JPG" alt="L'église de São Domingos" />
</a>
</p>
<ul>
<li>à l’ouest, il y a l’<a href="https://www.openstreetmap.org/way/115238861">elevador de Santa Justa</a>, joli monument de fer offrant une jolie vue sur le quartier en haut. L’accès tout en haut et payant (inclus dans les billets de transports 24h, mais l’attente est quand même longue). L’accès au premier étage (qui est déjà bien assez haut) est possible gratuitement et sans attendre en traversant la <a href="https://www.openstreetmap.org/node/2372779129">terrasse du restaurant</a> derrière le couvent des Carmes et en prenant <a href="https://www.openstreetmap.org/way/446066424">le pont</a>. Il y a même un ascenseur caché dans le magasin au rez de chaussée (sur la rua do Carmo), à la verticale du <a href="https://www.openstreetmap.org/node/4771408880">point de vue</a> (plus simple à trouver à la descente qu’à la montée ceci dit).</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06919.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j8/DSC06919_mini.JPG" alt="La place du Rossio vue depuis le premier étage de l'elevador de Santa Justa" />
</a>
</p>
<ul>
<li>à l’est, au niveau du début de l’Alfama, il y a la <a href="https://www.openstreetmap.org/way/96319699">cathédrale</a>.</li>
</ul>
<p>Le soir, on mange chez Solar Minhoto, notre nouveau repaire pratique, pas cher et bon à côté de la chambre :)</p>
<p>Une autre suggestion que notre hôte nous a donné est d’aller à la <a href="https://www.openstreetmap.org/node/4378847289#map=17/38.71636/-9.12327">Feira da Ladra</a>, un marché aux puces qui se tient tous les mardis et samedis (toute la journée). Le marché est <a href="https://fr.wikipedia.org/wiki/Feira_da_Ladra">très réputé</a>, mais on n’a pas eu l’occasion d’y passer.</p>
<h2>Samedi : Belem et Cacilha (à pied et transports publics)</h2>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC06999.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC06999_mini.JPG" alt="Des pasteis de nata !" />
</a>
</p>
<p>Info à noter : la plupart des monuments sont gratuits pour les portugais (seulement) le dimanche. C’est donc un jour à éviter dans certaines zones touristiques. Du coup, on a décidé d’aller faire un tour à Belem le samedi, pour avoir le dimanche dans Lisbonne, où on aura moins de monuments à visiter.</p>
<p>Pour aller à <a href="https://www.openstreetmap.org/node/206169708#map=15/38.6976/-9.2059">Belem</a>, le plus simple est de prendre le <a href="https://www.openstreetmap.org/relation/6549265">tramway 15</a> (qui est un tramway moderne, pas comme le 28 ou le 12) qui part depuis le front du Tage à Lisbonne et s’arrête juste devant le monastère des Jeronimos à Belem, puis devant la tour de Belem. Attention, le tramway est souvent bondé et il est connu pour être un lieu d’activité des pickpockets qui en profitent. Rangez vos affaires en sécurité et surveillez vos sacs à dos et tout se passera bien ! :) Si le tramway est bondé, les bus peuvent fournir de bonnes alternatives également.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC06936.JPG">
<img style="max-width: 25%; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC06936_mini.JPG" alt="Le monastère des Jeronimos" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC06961.JPG">
<img style="max-width: 25%; margin-left: 1em; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC06961_mini.JPG" alt="Le monastère des Jeronimos" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC06979.JPG">
<img style="max-width: 25%; margin-left: 1em; vertical-align: middle;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC06979_mini.JPG" alt="Le monastère des Jeronimos" />
</a>
</p>
<p>Premier monument à visiter de la journée, le <a href="https://www.openstreetmap.org/node/5661236343">Monastère des Jeronimos</a> (arrêt <a href="https://www.openstreetmap.org/node/454660367">du même nom</a> sur le tram). La page <a href="https://fr.wikipedia.org/wiki/Monast%C3%A8re_des_Hi%C3%A9ronymites">Wikipédia</a> est assez complète et avec des photos. L’idéal est d’y arriver vers 9h (pour l’ouverture à 10h). Il y a déjà la queue, mais au moins vous serez dans les premiers entrés et un peu tranquilles pour la visite ! L’entrée est à 10€ (tarif réduit à 5€). Le monastère est très joli, mais pas très grand (surtout comparé à ceux de Tomar, Alcobaça et Batalha). Il y a essentiellement un cloître et quelques salles autour et s’il y a trop de queue, il vaut probablement mieux passer du temps à se balader en ville et autour du monastère que faire la queue. En sortant, vous pouvez entrer dans l’église du monastère (on la voit depuis l’étage du monastère pendant la visite). La visite de l’église est libre et gratuite.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC06990.JPG">
<img style="max-width: 40%;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC06990_mini.JPG" alt="Le monument des découvertes" />
</a>
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC06995.JPG">
<img style="max-width: 40%; margin-left: 1em;"
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC06995_mini.JPG" alt="La tour de Belem" />
</a>
</p>
<p>La <a href="https://www.openstreetmap.org/way/24341353">Tour de Belem</a> (page <a href="https://fr.wikipedia.org/wiki/Tour_de_Bel%C3%A9m">Wikipédia</a>) est probablement un des monuments les plus célèbres de Lisbonne. Elle se trouve à une dizaine de minutes à pied, en marchant le long du bord du Tage (ou un arrêt de tramway). La tour se visite (entrée à 6€), mais il faut encore faire la queue. On a sauté cette visite du coup… En chemin pour la tour, ne pas rater le <a href="https://www.openstreetmap.org/way/152327819">monuments aux découvertes</a> très célèbre lui aussi (page <a href="https://fr.wikipedia.org/wiki/Padr%C3%A3o_dos_Descobrimentos">Wikipédia</a>) et la vue depuis le quai sur le Tage, le <a href="https://www.openstreetmap.org/way/10073105#map=14/38.6940/-9.1774">Pont du 25 avril</a> et Cacilhas et le <a href="https://www.openstreetmap.org/node/2455728197">Christ roi</a> sur l’autre rive. On peut payer pour monter en haut, mais je ne suis pas sûr que l’on y gagne grand chose…</p>
<p>En face du monastère, ne pas rater le <a href="https://www.openstreetmap.org/node/1204384734">Museu Coleção Berardo</a>, un musée d’art moderne issu des collections de l’homme d’affaires portugais <a href="https://fr.wikipedia.org/wiki/Jos%C3%A9_Berardo">José Berardo</a>, qui en plus est gratuit pour tous le samedi (5€ sinon) ! Le musée est assez grand, avec des grands noms des différents mouvements de l’art moderne. Beaucoup d’explications (en français) sur les différents courants. À ne pas rater !</p>
<p>Le midi, on a mangé à <a href="https://www.openstreetmap.org/node/1514445079">Pao Pao Queijo Queijo</a>, un petit fast-food qui propose un menu impressionnant de wraps et sandwiches. Très bon rapport qualité / prix pour un site touristique comme Belem et il propose même des alternatives végéta(r/l)iennes (ouf, on n’en avait pas beaucoup vu jusque là… :() ! La queue au rez de chaussée peut être assez impressionantes mais en fait cela va assez vite. On passe d’abord à la caisse pour payer, puis on choisit ce qu’on veut et ce qu’on veut mettre dedans au stand avant d’aller chercher une place (salle à l’étage).</p>
<p>Après, il ne faut surtout pas rater la pâtisserie la plus célèbre qui fait les renommés <em>pasteis de nata</em> : <a href="https://www.openstreetmap.org/node/398922337">Pasteis de Belem</a>. Il y a une queue conséquente devant, mais c’est pour de la vente à emporter. Le mieux est de rentrer pour non seulement voir les pâtissiers cuisiner les <em>pasteis</em> (derrière une vitre) et les déguster sur place. La queue est moins longue en général et ils seront servis tiédis avec au choix du sucre ou de la canelle ! Un délice ! Le prix est surprenamment raisonnable pour une pâtisserie aussi touristique, compter 6€ pour un café, 3 <em>pasteis</em> et un jus d’orange frais (environ 1€ le <em>pasteis</em>).</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC07004.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC07004_mini.JPG" alt="Lx Factory" />
</a>
</p>
<p>En revenant vers Lisbonne, on s’est arrêté à <a href="https://www.openstreetmap.org/way/221960606">Lx Factory</a> (Lx signifie “Lisbonne” en language lisboète jeune et branché), une ancienne friche urbaine reconvertie en lieu alternatif avec des bars et des boutiques. Sur le papier, ça ressemblait fortement à une <a href="http://www.urbanspree.com/">Urban Spree</a> de Berlin ou un <a href="https://lesgrandsvoisins.org/">Grands Voisins</a> local. Finalement, le rez de chaussée est assez commercial, avec des bars tendances et chers et des boutiques <em>vintage</em> chères aussi. On n’a pas vraiment retrouvé ni le côté alternatif de Berlin, ni le côté associatif de Grands Voisins, un peu déçus… On notera quand même le bar avec terrasse au <a href="https://www.openstreetmap.org/way/433133805">dernier étage</a> (accès pas très évident, par un escalier un peu caché à peu près en face de <a href="https://www.openstreetmap.org/node/4985098430">Muito Muito</a>. Le bar est hors de prix, mais heureusement on peut prendre rapidement une photo depuis le dernier étage sans consommer, et il y a une vue super sur le <a href="https://www.openstreetmap.org/way/10073105#map=14/38.6940/-9.1774">Pont du 25 avril</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC07007.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC07007_mini.JPG" alt="Le toi-terrasse de Lx Factory" />
</a>
</p>
<p>On est ensuite remonté sur la <a href="https://www.openstreetmap.org/node/5078731327">Basilica da Estrela</a> (encore une église magnifique ! Par contre, payer 4€ pour monter en haut n’apporte pas grand chose. Il y a aussi un grand parc en face, pour une pause bien méritée.</p>
<p>Notre dernier objectif de la journée était de prendre le bateau pour <a href="https://www.openstreetmap.org/relation/6444453">Cacilhas</a>. On est donc redescendu vers l’<a href="https://www.openstreetmap.org/way/39658869">embarcadère</a> lentement en se promenant dans le Bairro Alto. Ne surtout pas rater le <a href="https://www.openstreetmap.org/relation/2449059">funiculaire de Bica</a>, gratuit avec une carte de transport 24h et très impressionnant !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC07017.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j9/DSC07017_mini.JPG" alt="Le funiculaire de Bica" />
</a>
</p>
<p>On prend le ferry à <a href="https://www.openstreetmap.org/way/39658869">Cais do Sodre</a> (billet en supplément si vous n’avez une carte 24h que pour Lisbonne, 1€25 et environ 15 minutes de trajet). Les ferrys sont très réguliers (toutes les 15 minutes dans la journée) et fonctionnent jusque tard, un peu plus espacés en soirée. Le ferry est vraiment sympa pour profiter de la vue sur Lisbonne et la <a href="https://www.openstreetmap.org/way/96896573">Place du commerce</a>. De l’autre côté du Tage, il y a une frégate et un sous-marin qui peuvent se visiter (mais on y était trop tard). Les plus courageux pourront marcher jusqu’au <a href="https://www.openstreetmap.org/way/87891338">Christ roi</a> (ou prendre un bus, il y en a quand même pour un moment), inspiré de celui de Rio de Janeiro et avec un super point de vue sur le pont et la ville. À noter à-propos du ferry : les toilettes sont payants (50 centimes) à la gare maritime de Cais do Sodre, mais gratuits du côté de Cacilha (pas de toilettes dans le ferry) !</p>
<p>Il y a beaucoup de petits restaurants pour manger proche de l’embarcadère à Cacilha et dans la <a href="https://www.openstreetmap.org/way/270915821#map=19/38.68648/-9.14858">rue Candido dos Reis</a>. Un certain nombre sont fermés le soir (ou n’ont plus grand chose) par contre. Ils ont l’air assez inégaux et certains ont l’air d’être des restaurants à touristes (avec un rabatteur devant). En regardant plus en détails, on s’aperçoit assez vite aussi qu’il y a des grands restaurants qui ont deux ou trois adresses, mais une même carte. On n’a pas trop cherché et on est allé chez <a href="https://www.openstreetmap.org/node/2760634860">A Toca</a> (en fait au bar de l’autre côté de la rue, mais c’est le même propriétaire et les cuisines sont chez A Toca). Ce n’était probablement pas le meilleur restaurant de la semaine, mais le (généreux) pavé de saumon grillé était à 9€, très raisonnable.</p>
<p>Une autre option pour manger était au <a href="https://www.openstreetmap.org/node/5089110281">Mercado da Ribeira</a>, à Lisbonne, juste en face de l’embarcadère de Cais do Sodré. Une ancienne halle a été aménagée avec de nombreux stands aux noms de grands chefs lisboètes. On peut acheter un plat (plutôt cher, compter au moins 10€) au stand de son choix puis s’installer à l’une des grandes tables au centre de la salle. Le tout a un petit air de Chelsea Market à New York. C’est par contre un peu décevant dans l’ensemble avec des plats plutôt chers par rapport à ce qu’on peut trouver dans un bon restaurant dans les rues de Lisbonne, pour une qualité qui n’a pas l’air si exceptionnelle (le tout sans service…). C’est tendance par contre !</p>
<p>Il y avait le village de l’Eurovision sur la <a href="https://www.openstreetmap.org/way/96896573">place du Commerce</a> avec retransmission en direct de la finale. On a regardé, mais malgré tous ses supporters sur place, la France a perdu :(</p>
<h2>Dimanche : Lisbonne suite (à pied et transports publics)</h2>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j10/DSC07065.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j10/DSC07065_mini.JPG" alt="Le parc Edouard VII" />
</a>
</p>
<p>Le dimanche, on se consacre donc à la visite de Lisbonne, essentiellement à pied (et un peu en métro). Le matin, on commence par tenter de prendre le tramway historique (28E ou à défaut le 12E), depuis la place <a href="https://www.openstreetmap.org/node/1122508428">Martim Moniz</a>. Entre les travaux et le flot de touristes, c’est un échec (voir plus bas pour les conseils pour maximiser vos chances)… :(</p>
<p>On prend donc la direction du <a href="https://www.openstreetmap.org/way/19750461">parc Edouard <span class="caps">VII</span></a>, un grand parc en pente un peu en hauteur, dans l’alignement de l’<a href="https://www.openstreetmap.org/way/252732028sées">Avenida da Liberdade</a>. Avec l’alignement de la grande avenue jusqu’au bord du Tage, le parc Edouard <span class="caps">VII</span> offre un <a href="https://www.openstreetmap.org/node/5446794773">point de vue</a> et une perspective assez incroyable sur la ville.</p>
<p>On notera au passage qu’un certain nombre de stations de métro de Lisbonne sont particulièrement jolies, presque sorties d’un musée. En particulier, la station <a href="https://www.openstreetmap.org/node/256972634#map=14/38.7388/-9.1102">Olaias</a>, sûrement la plus belle bien qu’un peu en dehors des zones touristiques. <a href="https://www.routard.com/guide/lisbonne/1853/transports_et_deplacements.htm">Certaines stations</a> vers le parc Edouard <span class="caps">VII</span> sont assez jolies aussi : <a href="https://www.openstreetmap.org/node/247051835">Marquês de Pombal</a>, <a href="https://www.openstreetmap.org/node/256674213">Parque</a> et <a href="https://www.openstreetmap.org/node/265896596">Picoas</a> notamment.</p>
<p>Attention, il n’y a pas grand chose pour manger autour de la station <a href="https://www.openstreetmap.org/node/256976570">São Sebastiao</a>, en particulier un dimanche (la plupart des petits cafés étant fermés). On a trouvé le <a href="https://www.openstreetmap.org/node/2066988760">Piccolo Napoli</a> qui en plus proposait 30% de réductions sur <a href="https://www.thefork.com/restaurant/piccolo-napoli/210349">LaFourchette</a>. Du coup, c’était un très bon plan et un excellent rapport qualité / prix ! Les pizzas étaient excellentes, et les desserts très bons, pour moins de 10€ par personne.</p>
<p>Le dimanche après-midi (après 14h), le musée <a href="https://www.openstreetmap.org/way/55593971">Calouste Gulbenkian</a> et sa <a href="https://www.openstreetmap.org/way/188143627">collection d’art moderne</a> sont gratuits pour tous. Le musée présente les collections privées de l’homme d’affaires Calouste Gulbenkian. En suivant l’enchaînement de salles de l’exposition permanente, on passe de l’art de l’antiquité à l’art d’Orient puis aux peintures européennes (dont des pièces d’artistes célèbres, Manet, Monet, Renoir, Rubens, Rembrandt, etc.) avant de terminer par l’art nouveau et les ivoires et bijoux de René Lalique. La collection d’art moderne abrite une importante collection de statues et quelques installations.</p>
<p>Ensuite, retour dans le Bairro Alto, du côté de la <a href="https://www.openstreetmap.org/way/160122832">place do Principe Real</a>. Au centre du jardin, il y a <a href="https://www.openstreetmap.org/way/160122854">un ancien réservoir d’eau</a> qui se visite, gratuit et amusant ! Il y a de nombreuses églises dans le coin aussi, notamment l’église de <a href="https://www.openstreetmap.org/way/100609457">São Pedro</a> et le point de vue de l’autre côté de la rue (visite libre de l’église et de la magnifique chapelle, visite payante pour le chœur et la sacristie, <a href="http://www.lisbonne-idee.com/p5154-convento-sao-pedro-alcantara.html">plus d’infos</a>). En continuant le long de la rue, on ne ratera pas l’<a href="https://www.openstreetmap.org/way/95408893">église de São Roque</a> et ses nombreuses chapelles, magnifique ! L’une des chapelles (la plus chargée en métaux précieux, au fond à gauche) a même été construite à Rome puis démontée et transportée par bateau avant d’être reconstruite dans l’église ! Des détails sur l’église et son histoire sont sur <a href="https://fr.wikipedia.org/wiki/%C3%89glise_Saint-Roch_de_Lisbonne">Wikipédia</a>. Un regret cependant, la plupart des éléments de décoration et les reliques ont été déplacées de l’église pour être mises dans le <a href="https://www.openstreetmap.org/way/95408893#map=19/38.71343/-9.14330">musée voisin</a> et on ne les voit donc pas en situation. L’entrée du musée est gratuite pour les étudiants et les enseignants (2.5€ sinon) mais plutôt à réserver aux passionnés d’orfèvrerie religieuse ou de reliques. L’exposition des objets dans les vitrines et non en contexte dans l’église fait perdre pas mal d’intérêt à la collection… Il ne faut pas hésiter à s’engager dans les rues parallèles, dans le cœur du Bairro Alto, souvent un peu à l’écart des groupes de touristes et très agréables !</p>
<p>Pour goûter, on a testé la <a href="https://www.openstreetmap.org/node/4226508186#map=19/38.71533/-9.14609">Pastelaria São Roque</a> (<a href="http://panifsroque.pt/">site officiel</a>), une toute petite pâtisserie authentique dans un joli bâtiment. Il n’y a pas beaucoup de places, mais les <em>pasteis de nata</em> sont excellents et servis tièdes ! En plus, les <em>pasteis de nata</em> sont à 1€ pièce et le jus d’orange frais à 2€ ce qui est très raisonnable comme prix !</p>
<p>Pour manger le soir, on a testé <a href="https://www.openstreetmap.org/node/5674587416">Artis Wine Bar</a>, un bar à tapas dans le Bairro Alto. Il y a un large choix de vins portugais (pas beaucoup de choix en non alcoolisé par contre, évidemment…). Les tapas (ou <em>petiscos</em> au Portugal, mais c’est pareil :) sont plutôt copieux, assez variés et à des prix raisonnables, compter entre 5 et 10€ par portion. On trouve des <em>patatas bravas</em> (pommes de terre à la sauce <em>très</em> épicée), du poulpe grillé, des saucisses et autres charcuteries portugaises, etc. Compter 3 à 4 portions de <em>tapas</em> pour deux, pour un repas à environ 40€ pour deux avec boissons. Attention, ils ne prennent pas la carte bleue (seulement les cartes de débits portugaises).</p>
<p>Ce quartier est un quartier qui bouge pas mal et notamment le soir. On a été boire un verre au <a href="https://www.openstreetmap.org/node/2501889503">Pavilhão Chinês</a> que notre hôte nous avait recommandé. L’ambiance est assez étonnante dans ce bar dont la décoration intérieure ressemble à un salon anglais mais dont les murs sont couverts de toutes sortes de collections, méticuleusement disposées pour couvrir chaque centimètre carré de mur. On verra successivement des collections de soldat de plomb, de casques de soldats, de petits trains, de tasses, etc. Le mobilier fait un peu “bar à whisky”, avec de larges fauteuils en cuirs et pas mal de places entre les tables. À voir ! La carte des cocktails (accompagnée d’une collection d’illustrations coquines des années 30) est longue comme le bras, avec quelques options sans alcool. C’est assez cher pour le Portugal, on est plus proches des prix parisiens (bière de gingembre à 5€ et cocktails à 9.5€) mais il faut voir ce bar !</p>
<h2>Lundi : Lisbonne fin (à pied et transports publics)</h2>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j11/DSC07107.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j11/DSC07107_mini.JPG" alt="Vue sur les toits de l'Alfama" />
</a>
</p>
<p>Le matin, on a enfin réussi à prendre le tram dans les petites ruelles de
l’<a href="https://www.openstreetmap.org/node/207597971#map=17/38.71195/-9.12770">Alfama</a>.
Il passe tout juste entre les maisons et les voitures, et c’est très
impressionnant. En ce moment (mai 2018), il y a des travaux et le <a href="http://www.carris.pt/pt/electrico/28E/descendente/">tram
28E</a> est coupé en deux
parties : un tronçon jusque dans l’Alfama (court et sans grand intérêt), puis
un tronçon jusqu’au terminus, en suivant le trajet du 12E au lieu de son trajet
habituel (le trajet normal du tramway 28E est visible
<a href="https://www.openstreetmap.org/relation/6552489#map=15/38.7156/-9.1492">ici</a>).
Pour éviter la queue monstrueuse du tram 28E, le <a href="http://www.carris.pt/pt/electrico/12E/ascendente/">tram
12E</a> fournit une assez bonne
alternative : vieux tram et petites rues de l’Alfama (le trajet est visible
<a href="https://www.openstreetmap.org/relation/1411178#map=17/38.71330/-9.13407">ici</a>)
! Aussi, il faut savoir qu’il y a plus de trams en semaine (que le weekend) et
que la plupart des gens montent à <a href="https://www.openstreetmap.org/node/1135912715">Martim
Moniz</a> ou à <a href="https://www.openstreetmap.org/node/262253942">Praça da
Figueira</a>. Prendre le tram à <a href="https://www.openstreetmap.org/node/4309574818">Rua
da Conceiçao</a> permet donc de
monter dans un tram quasi vide et d’avoir de la place pour s’asseoir (ce qui en plus vous offre une certaine sécurité vis à vis des pickpockets qui sévissent dans les tramways touristiques) !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j11/DSC07100.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j11/DSC07100_mini.JPG" alt="Un vieux tramway de Lisbonne" />
</a>
</p>
<p>On est descendu au <a href="https://www.openstreetmap.org/node/4381810008">Miradouro de Santa
Luzia</a> qui offre une jolie vue
sur l’Alfama, le Tage et le <a href="https://www.openstreetmap.org/way/9253917">Panthéon
National</a>, puis on s’est baladé dans
les petites ruelles (encore assez typiques) de l’Alfama.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j11/DSC07112.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j11/DSC07112_mini.JPG" alt="Dans une ruelle de l'Alfama" />
</a>
</p>
<p>Le midi, on a (enfin) pu tester le “menu economico” de <a href="https://www.openstreetmap.org/node/5653851095">Solar Minhoto</a>, 7.5€
pour pain, olives, soupes, plat, dessert et café ! Imbattable !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j11/DSC07119.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j11/DSC07119_mini.JPG" alt="Un étrange immeuble derrière la gare d'Oriente" />
</a>
</p>
<p>L’après-midi, on est parti à
<a href="https://www.openstreetmap.org/node/256975177">Oriente</a> et faire un tour au
<a href="https://www.openstreetmap.org/relation/6427494">Parque das Naçoes</a>, un grand
quartier moderne qui a été réhabilité à l’occasion de l’Exposition
internationale de 1998. Bon à savoir, il y a une consigne à bagages dans les gares (et notamment à la gare Oriente). Paiement au retrait en espèce uniquement mais il y a une machine pour changer des billets en pièces. Le plus petit casier (qui tient largement deux bagages format cabine) coûte 1.5€ pour la première heure, puis 1€ par heure supplémentaire.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j11/DSC07144.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j11/DSC07144_mini.JPG" alt="La promenade en bord de Tage avec la tour et le pont Vasco de Gama au fond" />
</a>
</p>
<p>Les principaux bâtiments à voir dans le quartier sont :</p>
<ul>
<li>La <a href="https://www.openstreetmap.org/way/39735033">gare d’Oriente</a></li>
<li>Le <a href="https://www.openstreetmap.org/way/240816973">centre commercial Vasco de Gama</a>, si vous voulez faire un tour dans un centre commercial</li>
<li>Le <a href="https://www.openstreetmap.org/way/33528328">Pavillon Atlantique</a> (maintenant Altice Arena) qui est maintenant une salle de concert (c’est là qu’était la finale de l’Eurovision), en forme de coquillage</li>
<li>Le <a href="https://www.openstreetmap.org/relation/3266709">Pavillon du Portugal</a> et sa chape de béton</li>
<li>L’<a href="https://www.openstreetmap.org/way/230062385">aquarium</a> (un des plus grands d’Europe et à <a href="https://en.wikipedia.org/wiki/Lisbon_Oceanarium#Architecture">l’architecture remarquable</a>) et le <a href="https://www.openstreetmap.org/relation/3232954">Pavillon de la Connaissance</a> (musée un peu comme le palais de la découverte)</li>
<li>Le <a href="https://www.openstreetmap.org/way/230062383">petit jardin aquatique</a> derrière l’aquarium, autour du <a href="https://www.openstreetmap.org/way/39735039">Passeio de Ulisses</a></li>
<li>La <a href="https://www.openstreetmap.org/way/39739321">tour Vasco da Gama</a>, 145m de haut, un des plus hauts bâtiments portugais. Elle abrite maintenant un hôtel et est fermée au public.</li>
<li>Il y a <a href="https://www.openstreetmap.org/way/33235559#map=16/38.7679/-9.0919">une télécabine</a> pour relier l’aquarium et la tour Vasco de Gama, payant (pass de transports publics non utilisables sur le téléphérique). Si vous n’avez pas peur de marcher un peu, il y a un chemin piéton très agréable le long du Tage, sous la télécabine.</li>
<li>Au-delà la tour Vasco de Gama, il y a le <a href="https://www.openstreetmap.org/way/24748518">Passeio do Tejo</a> qui permet de profiter de jolies vues sur le <a href="https://www.openstreetmap.org/way/344085225">pont Vasco da Gama</a>, long de 17 km, 27e plus grand pont du monde.</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j11/DSC07164.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/j11/DSC07164_mini.JPG" alt="L'immense pont Vasco de Gama" />
</a>
</p>
<p>L’aéroport de Lisbonne est sur le réseau métro (ticket normal). Par contre, les départs low costs se font depuis le
<a href="https://www.openstreetmap.org/way/72108529">terminal 2</a>, accessible par une navette gratuite entre les deux terminaux. En revanche,
les arrivées low costs se font visiblement avec un débarquement systématique par bus, qui
dépose les passagers directement au terminal 1.</p>
<p>Attention, le terminal 2 est un hangar
au bord de l’autoroute. C’est assez visible quand on regarde une carte (et assez bien décrit <a href="http://lisbonlisboaportugal.com/fr/terminal-2-de-aeroport-de-lisbonne-fr.html">ici</a>), mais c’est assez déconcertant quand on n’a pas prévu le coup :( Ne comptez pas trop y aller trop en avance en vous disant “on sera installé avec du wifi et une prise pour traiter les courriels et regarder des vidéos”, ça ne marche pas :/ Si vous avez longtemps à attendre à l’aéroport, la meilleure option est probablement d’aller au terminal 1 pour patienter, puis de prendre la navette entre les terminaux au dernier moment. À noter, le terminal 2 a des horaires d’ouverture assez larges mais ferme quand même quelques heures la nuit.</p>
<p>Avant la sécurité, il n’y a quasiment aucun siège, pas de wifi, peu de commerces et pas de prises électriques. Après la sécurité, il y a quelques prises (mais pas assez et les gens se branchent sur les multiprises qui dépassent des télés) et quelques sièges, très vite pris d’assaut. La seule option raisonnable (en terme d’attente et de prix) pour manger est <a href="https://www.openstreetmap.org/node/4522429967">Mc Donald’s</a>, il vaut probablement acheter un truc à emporter en ville avant d’arriver à l’aéroport. Le terminal 2 après la sécurité est très similaire au terminal 2G de Roissy-<span class="caps">CDG</span>, si par hasard vous le connaissez (un grand hangar dans lequel tout le monde attend, avec peu de boutiques et de services).</p>
<p>Retour à Paris, c’est fini pour ces 10 jours au Portugal :’( mais on y retournera !</p>
<h2>Quelques subtilités avec les locations de voiture au Portugal</h2>
<p>Attention, il y a quelques subtilités avec les locations de voitures au
Portugal. Déjà, apparemment les loueurs les moins chers (Goldcar, Rhodium) ne
sont pas particulièrement recommandés et il vaut mieux louer chez un grand
loueur (Europcar, Sixt (testé, désapprouvé, voir plus bas), Hertz, Avis, etc.).
Vous avez souvent l’option de payer au guichet (et non en ligne) lorsque vous
réservez, moyennant quelques euros de plus. Le gros avantage, c’est que votre
réservation est alors annulable et remboursable sans frais, ce qui vous permet
de vérifier régulièrement et éventuellement de refaire une réservation si les
prix baissent (les prix de location de voitures en période touristique font le
yoyo, parfois d’un facteur 3). Si vous prenez la voiture à un endroit et la
laissez à un autre, attention aux frais d’abandon (qui sont restés très
raisonnables dans notre cas malgré tout).</p>
<p>Nous avions pris une voiture de la catégorie la moins chère (“Economy”) et nous avons eu une Polo toute neuve. Elle manquait un peu de punch, mais vu les distances et les routes parcourues, ce n’était pas très bloquant.</p>
<p>Enfin, n’oubliez pas les recommandations habituelles, valables dans tous les pays. En particulier, faire bien attention aux assurances que vous prenez (l’agence de location vous forcera sûrement un peu la main pour prendre l’assurance complète avec rachat de franchise) et à combien vous devrez payer si vous avez un problème avec la voiture (autour de 1000€ sans assurance spécifique). Les cartes bleues “Premier”/”Gold” incluent déjà en principe des assurances avec rachat de franchise si vous payez la location de voiture avec elles. Enfin, si vous n’avez pas pris l’assurance complète, faites bien le tour de la voiture au moment de la prendre et faites noter sur le contrat toutes les rayures et problèmes que vous verriez (sinon, ils risquent d’être à votre charge au retour).</p>
<h3>Les stations essences se situent en dehors des villes</h3>
<p>Premier point important, il semble y avoir une législation au Portugal qui limite l’implantation des stations essence, en particulier dans les centre villes (mais de toutes façons, oubliez la voiture à Lisbonne ou Porto !). On n’a jamais eu de problèmes pour trouver de l’essence, mais il sera probablement difficile de faire le plein juste avant de rendre la voiture en centre ville.</p>
<p>Votre voiture de location devrait être fournie avec un plein, et les loueurs laissent souvent le choix entre rendre la voiture avec un plein ou à vide. Comparez les prix et choisissez au mieux.</p>
<p>En revanche, il faut absolument noter qu’il n’y a que <strong>deux</strong> options qui existent, quelque soit le loueur, quoique vous raconte l’agence chez qui vous prenez la voiture :</p>
<ul>
<li>Soit vous ramenez la voiture avec un plein, vous ne payerez rien de plus pour l’essence au retour de la voiture.</li>
<li>Soit vous ramener la voiture avec le moins d’essence possible et vous devrez payer le plein au loueur, à un tarif mentionné sur le contrat.</li>
</ul>
<p>L’agence Sixt de Porto nous a assuré que si on ramenait la voiture à la moitié du plein, on ne payerait que la moitié du plein au retour (et non un plein complet). C’était évidemment une arnaque et on a perdu un demi plein…</p>
<h3>Le télépéage</h3>
<p>Quand vous louez une voiture, vous avez la possibilité de louer un badge de télépéage “Via Verde” pour environ 1€ / jour (avec un plafond d’environ 15€ sur la durée de la location). Chaque fois que vous passerez à un péage, vous pourrez prendre des voies spécifiques et vous aurez une facture à la fin de votre voyage avec tous les péages, à régler directement au loueur. Pour ça, ça fonctionne comme en France.</p>
<p>En revanche, au Portugal, il y a des sections d’autoroutes qui sont à payer par tronçon (de quelques kilomètres) avec des portiques de paiement automatique placés régulièrement sur la route (un peu comme nos radars tronçons, sauf que là c’est pour des péages). Si vous avez un badge “Via Verde”, il s’activera automatiquement à chaque portique et le péage sera répercuté sur votre facture finale. Sinon, vous devrez aller payer dans un bureau de poste dans les jours suivants, ce qui n’est pas des plus pratiques. Il ne semble y avoir aucun autre moyen plus pratique pour payer que d’aller à la poste. Ces routes ne sont pas très nombreuses (sur notre trajet total, on a du le voir 2 ou 3 fois seulement, quelques dizaines de kilomètres en tout), et sont signalées donc peuvent s’éviter, mais si vous voulez être tranquille et ne pas vous poser de questions, autant prendre l’option pour avoir le badge !</p>
<h2>Budget</h2>
<h3>Vols</h3>
<p>Au moment des ponts de mai, on en a eu pour 278€ par personne avec Transavia (sans bagage en soute). AirFrance et <span class="caps">TAP</span> n’étaient pas beaucoup plus chers, c’était sûrement un meilleur choix. En dehors d’un tel pic touristique, les billets ont l’air d’être beaucoup moins chers.</p>
<h3>Voiture</h3>
<p>Pour louer la voiture pendant 5 jours (kilométrages illimités), on a payé environ 150€, en ayant perdu le demi plein. Attention, les locations sont comptés par jour (24h) et c’est l’heure à laquelle vous prenez effectivement la voiture qui compte. L’essence a un prix assez stable sur l’ensemble du territoire (pas trop de grandes variations entre les stations comme on peut le voir en France). Elle a tendance à être un peu plus chère qu’en France, autour de 60€ pour un plein d’une petite voiture essence (Volkswagen Polo dans notre cas).</p>
<h3>Hébergement</h3>
<p>Pour l’hébergement, compter 30 à 40€ par nuit pour une chambre double bien située sur <a href="http://airbnb.fr/">Airbnb</a> à Porto ou Lisbonne. C’est globalement l’option la moins chère, souvent moins chère qu’une chambre en auberge de jeunesse (sauf en dortoirs) ou qu’un hôtel basique. En dehors de ces grandes villes, la meilleure option est plutôt les chambres d’hôtes (et les petits hôtels, souvent pas très chers). Compter autour de 30€ par nuit dans ce cas pour une chambre double. Dans les chambres d’hôtes, vous aurez souvent accès à une cuisine partagée, et le gros avantage c’est que les réservations sont souvent très flexibles par défaut. Il est parfois possible d’annuler gratuitement jusqu’au soir même !</p>
<p>D’autres options plus chères sont les <em>quintas</em>, d’anciennes grandes propriétés agricoles aujourd’hui transformé en hôtel de luxe (apparemment de qualité inégale), ou les <em>pousadas</em>, pareil mais dans des monuments historiques ou classés (compter plus de 100€ / nuit, mais c’est apparemment très bien :).</p>
<h3>Repas</h3>
<p>Il y a énormément de petits restaurants au Portugal qui servent une cuisine simple (plats du jour, poisson grillé, etc.) à des prix très bas, entre 5 et 10€ par personne. Le poisson grillé en particulier est quasiment systématiquement du poisson frais, de bonne qualité. D’autres restaurants proposent le midi des menus “touristiques” ou “économiques” incluant une soupe, un plat, un dessert et boisson et café pour moins de 10€, ce sont en général de bonnes options (souvent moins chères et plus pratiques que d’aller au supermarché) ! Un restaurant proposant des plats plus élaborés se situe autour de 15€ par personne à la carte (plat + dessert, boisson). Attention, deux choses à noter sur les restaurants au Portugal :</p>
<ul>
<li>on ne vous servira quasiment jamais de carafe d’eau (du robinet). Vous devrez donc acheter une bouteille d’eau. Par contre, la plupart du temps, les bouteilles d’eau (plate) servie au restaurant sont de simples bouteilles en plastique, comme celles que vous trouvez au supermarché (et donc non consignées). Le plus rentable est donc en général de prendre une grande bouteille (1.5L) et de l’emmener si vous ne l’avez pas finie.</li>
<li>lorsque vous vous installerez à table, on vous amènera systématiquement du pain, mais aussi des planches de fromage, charcuterie et autres amuse bouches (olives etc.). Ces planches (et le pain) sont payantes mais souvent un peu cachées dans les menus. Si vous ne voulez pas payer de supplément, dites simplement que vous n’en voulez pas et les serveurs repartiront avec. Dans d’autres restaurants, du fromage sera déjà posé sur la table quand vous arriverez, mettez-le simplement de côté et n’y touchez pas et il ne devrait pas être compté.</li>
</ul>
<p>Le café est souvent très bon marché (et les expressos sont très bons !), entre 60 centimes et 1€. Le jus d’orange est quasiment systématiquement à base d’oranges fraiches, pressées à la demande (dans les cafés et les pâtisseries) et coûte autour de 2€ le verre. Dans les pâtisseries, il est souvent assez difficile de savoir combien coûtent les pâtisseries en vitrine. En général, quelle que soit la pâtisserie, c’est autour de 1€.</p>
<p>Au Portugal, Schweppes fait de la bière de gingembre (sans alcool donc), que vous trouverez facilement dans les bars :)</p>
<h2>Divers</h2>
<p>Quelques notes en vrac :</p>
<ul>
<li>Dès que les rues sont pavées, toute la signalisation est souvent faite avec
des pavés de différentes couleurs !</li>
</ul>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/06/10_jours_portugal/DSC07073.JPG">
<img
src="http://localhost/Blog/output/images/2018/06/10_jours_portugal/DSC07073_mini.JPG" alt="Du marquage au sol en pavés !" />
</a>
</p>
<ul>
<li>Pas de soucis avec les prises, ce sont les mêmes qu’en France.</li>
<li>Les portugais parlent très bien anglais (bien mieux que les français). Ils parlent même souvent français, donc on arrive assez facilement à se faire comprendre, même un peu à l’écart des sentiers battus. Par contre, ils préfèreront parler anglais ou français qu’espagnol.</li>
<li>Au Portugal, il n’y a que des français partout ! Vous passerez la plupart du temps à entendre parler français autour de vous (surtout si vous piochez des adresses dans un guide francophone)…</li>
<li>Au Portugal, tout établissement commercial ou de prestation de service doit mettre à disposition de ses clients un livre de réclamation. En cas de problèmes (même si vous êtes touristes), n’hésitez pas à demander le livre de réclamation de l’établissement et à rédiger une réclamation en 3 exemplaires. Un des exemplaires vous sera remis, un autre sera pour le commerçant et le troisième sera transmis aux autorités. Il est illégal de refuser l’accès au livre de réclamation. Plus d’infos à ce sujet <a href="https://www.lisbob.net/fr/blog/livre-reclamations-portugal">par ici</a>.</li>
<li>L’océan est assez froid entre Porto et Lisbonne (entre 15 et 20°C en mai). Si vous voulez vous baigner, visez plutôt <a href="https://www.openstreetmap.org/relation/5404608#map=9/37.8141/-8.1793">l’Algarve</a>.</li>
<li>On avait le <a href="http://www.guides-hachette.fr/livre/guide-du-routard-portugal-2018-9782017033493">Routard du Portugal</a>, qui était assez utile en fournissant un aperçu assez synthétique de ce qu’il y avait à faire dans tel ou tel coin, ainsi que des bonnes adresses de restaurants et cafés. Une partie du guide est accessible <a href="https://www.routard.com/guide/code_dest/portugal.htm">gratuitement en ligne</a> sur leur site, notamment des idées d’itinéraires et les informations utiles. Les restaurants conseillés par le Routard sont plutôt sympas (bons conseils), mais malheureusement souvent saturés de français. À noter également qu’on avait un guide datant de 2016 et que tous les prix avaient monté de 10% en deux ans :/ Il y a un <a href="http://www.guides-hachette.fr/livre/guide-du-routard-lisbonne-2018-9782017033448">guide dédié pour Lisbonne</a> et pour <a href="http://www.guides-hachette.fr/livre/guide-du-routard-porto-et-ses-environs-2018-9782016266885">Porto</a> mais (au moins pour le guide de Lisbonne) ils se recouvrent beaucoup avec le guide du Portugal, qui est donc a priori suffisant.</li>
</ul>
<p>Si vous n’avez pas de compte chez :</p>
<ul>
<li>Airbnb, vous pouvez utiliser <a href="https://www.airbnb.fr/c/lverney3">ce lien</a> pour créer un compte : 25€ de crédit offert à utiliser sur votre première réservation (et je gagne 15€ de crédit pour un prochain voyage une fois votre premier voyage effectué).</li>
<li>Booking, vous pouvez utiliser <a href="https://booking.com/s/39_0/mfouil80">ce lien</a> pour créer un compte : 25$ de crédit offert sur votre première réservation de 50$ minimum, ça marche aussi avec des euros et les gains sont juste à adapter avec le taux de change (et je gagne la même chose pour un prochain voyage une fois votre premier voyage effectué).</li>
<li>La Fourchette, vous pouvez utiliser le code <code>7AD7D171</code> pour bénéficier de 1000 yums (points de fidélité) grâce à votre première réservation ce qui vous donnera une remise de 10€ dans un restaurant participant (et je gagne 500 yums après votre première réservation).</li>
</ul>
<p>J’espère que ces conseils vous aideront à préparer votre prochain séjour au Portugal ! N’hésitez pas à me faire part de commentaires ou suggestions !</p>
<p>Cet article est sous licence <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">Creative Commons <span class="caps">BY</span>-<span class="caps">NC</span>-<span class="caps">SA</span></a>. N’hésitez pas à le repartager et à le modifier à votre convenance, tout en gardant un lien vers le document original, et en conservant la même licence, le tout pour une visée non commerciale.</p>Un (long) week-end sur la côte d’Émeraude : Saint-Malo, le mont Saint-Michel et Dinard2018-05-24T22:08:00+02:002018-05-24T22:08:00+02:00Phykstag:localhost,2018-05-24:/Blog/output/2018/05/un-long-week-end-sur-la-cote-demeraude-saint-malo-le-mont-saint-michel-et-dinard.html<p>Voici quelques notes sur un (long) week-end de trois jours en mai en Bretagne, sur la
côte d’Émeraude. Au programme : Saint-Malo, le mont Saint-Michel, Dinard,
Cancale et quelques pistes pour étendre le week-end ! :)</p>
<p>Voici quelques notes sur un (long) week-end de trois jours en mai en Bretagne, sur la
côte d’Émeraude. Au programme : Saint-Malo, le mont Saint-Michel, Dinard,
Cancale et quelques pistes pour étendre le week-end ! :)</p>
<h2>Jour 1 : Saint-Malo</h2>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/st_malo.jpg">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/st_malo.jpg" alt="Saint-Malo depuis le
môle des Noires"/>
</a>
</p>
<p>Départ de Paris le samedi matin en voiture, 4h de route environ (et 400 km),
pour arriver vers 12h. À Saint-Malo, on loge pour le week-end chez
<a href="https://www.airbnb.fr/rooms/19158066">Rozenn</a>, super Airbnb situé à 2 minutes
à pied de la gare et à 15 minutes à pied d’intramuros ! Comme toujours, on
est arrivé en même temps qu’un gros événement qu’on ne connaissait pas, le
festival <a href="http://www.etonnants-voyageurs.com/">Étonnants Voyageurs</a> (un grand
festival de films et de littérature autour des voyages) donc tous les hôtels
et les chambres étaient déjà réservées (mais il n’y avait pas tant de monde en ville).</p>
<p>L’après-midi, direction intramuros pour visiter Saint-Malo. On commence par
prendre une
<a href="https://fr.wikipedia.org/wiki/Galette-saucisse">galette-saucisse</a>, un
<a href="https://fr.wikipedia.org/wiki/Kouign-amann">kouign-amann</a> et un <a href="https://fr.wikipedia.org/wiki/Far_breton">far
breton</a> aux <a href="https://www.openstreetmap.org/node/1371126212">Délices du
Gouverneur</a> (à emporter
uniquement, compter une dizaine d’euros pour une galette, un dessert et une
boisson). Plutôt bon rapport qualité / prix pour intramuros !</p>
<p>La vue depuis le bout du <a href="https://www.openstreetmap.org/node/1543876547">Môle (jetée) des
Noires</a> sur Dinard, les îles,
l’embouchure de la Rance et la vieille ville est très sympa. On fait ensuite
le tour des remparts (très larges et sécurisés, avec des panneaux explicatifs
sur la ville et les personnages célèbres de la ville), puis on part en
direction du Petit et du Grand Bé, deux îles à quelques dizaines de mètres de
la côte accessibles par un chemin (pavé) découvert à marée basse.</p>
<p>Sur <a href="https://www.openstreetmap.org/way/305880286">le Petit Bé</a>, on peut
visiter le <a href="http://www.petit-be.com/">fort</a>. Le fort est accessible à pied
uniquement à marée basse (mais il semble qu’il y a un bateau passeur le reste
du temps, quand le fort est ouvert). Il se visite (visite guidée par le
propriétaire uniquement) pour 6€ (4€ en tarif réduit). La visite est super
instructive, le propriétaire est un vrai passionné des forts de la région, et
je recommande vivement ! En plus, il a des cartes anciennes de la ville de
Saint-Malo… qui n’ont pas grand chose à voir avec la ville actuelle (tous les
marais ont été asséchés et des bassins portuaires sont apparus) ! On peut même
<a href="https://www.airbnb.fr/rooms/5657819">passer une nuit dans le fort</a> !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/petit_be.jpg">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/petit_be.jpg"
alt="Saint-Malo depuis le Petit Bé" />
</a>
</p>
<p>Le <a href="https://www.openstreetmap.org/way/96786650#map=17/48.65188/-2.03379&layers=N">Grand
Bé</a>
se trouve juste à côté et offre un joli panorama sur la ville. On peut aussi y
voir le (très discret) <a href="https://www.openstreetmap.org/way/141693287">tombeau de
Chateaubriand</a>.</p>
<p>Enfin, la troisième île accessible à pied à marée basse, face à la plage de
l’Éventail abrite le <a href="https://www.openstreetmap.org/way/305880274">fort
national</a>. Celui-ci <a href="http://www.fortnational.com/">se
visite</a>, mais uniquement l’été, et il était donc fermé.</p>
<p>On a refait un tour dans les rues à l’intérieur des remparts cette fois,
notamment pour passer voir <a href="https://www.openstreetmap.org/way/351261994">la
cathédrale</a> (<a href="https://fr.wikipedia.org/wiki/Cath%C3%A9drale_Saint-Vincent_de_Saint-Malo">plus
d’infos</a>).</p>
<p>Le soir, on a mangé à la <a href="https://www.openstreetmap.org/node/4187221989">crêperie
Gallo</a> qui affiche de
nombreuses recommandations (petit futé, routard etc.) en vitrine. Compter 15€ /
personne pour galette, crêpe et boisson, mais les galettes sont plutôt
décevantes et pas très garnies. En repartant, on est passé devant <a href="https://www.openstreetmap.org/#map=19/48.64849/-2.02560">Ty
Nevez</a> pas très loin,
qui avait l’air top (recommandation des gens qui y mangeaient en terrasse,
locale et bio et pas très chère). À tester une prochaine fois !</p>
<p>Une balade sympa à faire (notamment au coucher du soleil) est la promenade
(pavée) le long de la <a href="https://www.openstreetmap.org/way/485330850">plage du
Sillon</a>, jusqu’aux <a href="https://www.openstreetmap.org/way/52813615">thermes
marins de Saint-Malo</a>, situé dans
un grand bâtiment datant de 1880.</p>
<p>C’était la <a href="https://nuitdesmusees.culturecommunication.gouv.fr/">nuit des
musées</a> et on en a donc
profité pour visiter les musées ouverts (et gratuits !) pour l’occasion. On a
commencé par le <a href="https://www.openstreetmap.org/way/141647459">Musée d’Histoire de la Ville et du Pays
Malouin</a> (<a href="https://www.saint-malo-tourisme.com/a-voir-a-faire/culture-et-patrimoine/musees/musee-d-histoire-1567548">plus
d’informations</a>)
en centre-ville, dans le donjon du château de la ville (désormais l’hôtel de
ville). Le musée raconte l’histoire de la ville, à travers deux zones
d’exposition : une première centrée sur la pêche de la morue dans les eaux
canadiennes et une deuxième plus générale sur l’histoire de la ville. Les
collections sont sympas, et cela permet de visiter le donjon du château. Mais
surtout, il y a une vue panoramique incroyable tout en haut, qui mérite à
elle seule de visiter ce musée !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/musee_ville.jpg">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/musee_ville.jpg"
alt="La vue depuis le musée de la ville" />
</a>
</p>
<p>On décide ensuite de partir en direction du <a href="https://www.openstreetmap.org/way/142245711">manoir de Jacques
Cartier</a> qui abrite <a href="http://www.musee-jacques-cartier.fr/">un
musée</a> sur le premier explorateur
européen du Canada. La visite est guidée (par des guides passionnés), et le
manoir est entièrement meublé pour reconstituer la maison de Jacques Cartier,
vraiment top ! Le musée vous rappellera quelques souvenirs si vous êtes déjà
allé <a href="http://localhost/Blog/output/2017/11/10-jours-au-canada.html">au Québec</a> (tout comme la
ville de Québec qui a des petits airs de Saint-Malo).</p>
<h2>Jour 2 : La baie du mont Saint-Michel</h2>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/mont_saint_michel.jpg">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/mont_saint_michel.jpg"
alt="Le mont Saint-Michel" />
</a>
</p>
<p>Le deuxième jour, on a décidé d’aller voir la baie du mont Saint-Michel (à une
petite heure de route et 50 km). On décide de suivre d’abord la route de la
côte pour s’arrêter aux <a href="https://www.openstreetmap.org/way/142254292">Rochers
sculptés</a> (<a href="https://fr.wikipedia.org/wiki/Rochers_sculpt%C3%A9s_de_Roth%C3%A9neuf">plus
d’informations</a>).
Il y a un <a href="https://www.openstreetmap.org/node/1474876734">petit parking au bout de la route
d’accès</a>, qui doit très vite
être saturé. Il y a un autre parking <a href="https://www.openstreetmap.org/way/321094279">au
restaurant</a>. On découvre en
arrivant que l’accès au site et payant (2€50 par personne, aucun tarif réduit).
Il y a une grande propriété à cet endroit et les accès publics au sentier du
littoral sont assez éloignés des rochers sculptés.</p>
<p>Il y a moyen d’y accéder gratuitement en <a href="http://next.liberation.fr/culture/2013/05/17/a-rotheneuf-il-y-a-angoisse-sous-roche_903774">passant par la plage voisine à marée
basse</a>
(et on le voit sur
<a href="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/geoportail.png">Geoportail</a>),
mais le site est assez escarpé. En plus, la mer est haute, donc on abandonne
les rochers sculptés.</p>
<p>On reprend la route direction
<a href="https://www.openstreetmap.org/#map=17/48.67247/-1.85300">Cancale</a> et <a href="https://www.openstreetmap.org/node/221908239#map=15/48.7084/-1.8444">la
pointe du
Grouin</a>.
Cancale est réputée pour ses huîtres creuses (classiques) mais aussi les
huîtres dites “plates” ou “pied de cheval”. Il y a un petit port, des plages
et des fermes ostréicoles. De la pointe du Grouin, à l’extrémité de la baie,
on peut voir le mont Saint-Michel par temps clair.</p>
<p>Pas de chance, comme d’habitude, on est tombé en plein milieu d’un événement
sans le vouloir : le défilé de Cancale ! Toutes les rues du centre-ville
étaient fermées à la circulation (et on a donc dû faire tout le tour de la
pointe pour repartir :)) et il y avait un monde fou. Sur le port de Cancale, il
y a plein de restaurants pour manger des crêpes, du poisson et des fruits de
mer. <a href="https://www.openstreetmap.org/node/5582729273">Au pied d’cheval</a> avait
l’air très bien, mais bondé. De même pour <a href="https://www.openstreetmap.org/node/2845953527">À Contre
Courant</a>. Finalement, on se
rabat sur le <a href="https://www.openstreetmap.org/node/5635072782">Vieux Safran</a> qui
propose un menu entrée (6 huîtres de Cancale, soupe de poissons, …) / plat
(moules frites, …) / dessert pour 15.90€ et était très bien !</p>
<p>À Cancale, on a trouvé à se garer <a href="https://www.openstreetmap.org/node/728284304">devant
l’église</a> (parcmètres, donc
gratuit dimanches et jours fériés).</p>
<p>En fin de journée, on part pour le <a href="https://www.openstreetmap.org/relation/376823">Mont
Saint-Michel</a> (<a href="https://www.ot-montsaintmichel.com/index.htm">informations
touristiques</a>), pour arriver
vers 17h à <a href="http://www.abbaye-mont-saint-michel.fr/">l’abbaye</a> et être dans
les dernières entrées (l’abbaye ferme à 19h, dernière entrée à 18h, gratuit
moins de 26 ans). Il y a un audioguide disponible à l’abbaye (3€ en
supplément, tarif unique), mais qui n’apporte pas énormément de choses par
rapport aux brochures papier (et aux visites guidées qu’on écoute de loin).
Astuce : il y a une prise casque sur l’audioguide donc possibilité d’utiliser
un dédoubleur :)</p>
<p>Avec les nouveaux aménagements du mont (pour remplacer la digue-parking qui le
reliait à la terre ferme par un pont), les parkings sont désormais sur le
continent, à <a href="https://www.openstreetmap.org/way/363549165">Pontorson</a>. Le site
officiel explique assez mal. Il y a des
<a href="https://www.openstreetmap.org/way/363547019">navettes</a> qui font la liaison
avec le mont (10 minutes de trajet) 24h/24 (ou on peut y aller à pied). Le
parking est payant (11.70€ / 24h, gratuit si entrée après 19h et sortie avant
2h), mais les navettes sont gratuites. Il y a deux arrêts intermédiaires pour
les navettes avant le mont : <a href="https://www.openstreetmap.org/node/3677176599">Route du
Mont</a> et <a href="https://www.openstreetmap.org/node/3420118425">Place du
barrage</a> pour desservir les
restaurants et hôtels sur le continent.</p>
<p>Le mont Saint-Michel est très très <strong>très</strong> touristique, et déborde de
touristes (littéralement, surtout sur un week-end prolongé). Les ruelles du
village moyenageux ressemblent très vite à un <span class="caps">RER</span> B en heure de pointe, et ce
n’est pas très agréable de visiter dans ces conditions. On nous avait
conseillé d’y aller en fin de journée, ce qui permet d’en profiter avec moins
de monde et de le voir de jour et de nuit. Testé et approuvé !</p>
<p>En arrivant vers 17h, il y avait encore beaucoup de monde dans les rues, mais
il n’y avait quasiment pas de queue pour entrer à l’abbaye. On a pu visiter
l’abbaye en prenant notre temps (compter une grosse heure de visite) et même
prendre des photos sans (trop de) personnes dessus ! Quand on est ressorti
vers 18h30, le soleil était encore haut et il n’y avait presque plus personne
dans les rues ! Si vous voulez profiter du mont et du village sans les
touristes, c’est l’idéal. Par contre, si vous êtes fan des boutiques de
souvenirs, elles étaient en train de fermer…</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/mont_saint_michel_3.jpg">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/mont_saint_michel_3.jpg"
alt="Le mont Saint-Michel désert" />
</a>
</p>
<p>À marée basse, il est possible d’aller à la <a href="https://www.openstreetmap.org/way/41662496">Chapelle
Saint-Aubert</a> à pied en longeant
par la porte de gauche quand on est face au mont, sur l’esplanade après
l’arrêt des navettes (c’est aussi là que sont les seuls robinets utilisables
pour se laver les pieds après être allé dans le sable). Il faut juste des
chaussures adaptées pour marcher sur des rochers ou du sable. La chapelle n’a
pas un grand intérêt mais permet de profiter de la vue sur le nord de la baie
et sur la forêt derrière l’abbaye du mont.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/chapelle.jpg">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/chapelle.jpg"
alt="La chapelle Saint-Aubert" />
</a>
</p>
<p><strong>Attention :</strong> La baie du mont Saint-Michel est dangereuse, avec de
nombreuses zones avec des sables mouvants, des trous d’eau et l’eau remonte
très vite (“à la vitesse d’un cheval au galop” dit-on). Surtout, la baie est
très plate et avec des bancs de sable et on ne se rend pas forcément compte
que la mer est en train de nous encercler. On peut facilement se balader à
proximité immédiate du mont (aller à la chapelle ou marcher un peu sur le
sable argileux) mais ne vous éloignez jamais sans un guide (et encore moins
tout seul). Comme à chaque fois, on a vu quelqu’un en difficulté pour revenir,
qui a eu une belle frayeur et son appareil photo réflex noyé pour pouvoir revenir.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/mont_saint_michel_2.jpg">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/mont_saint_michel_2.jpg"
alt="La baie du mont Saint-Michel" />
</a>
</p>
<p>On est resté jusqu’au coucher de soleil, pour voir le mont éclairé de nuit.
Les navettes (gratuites) sont très régulières en journée (toutes les 5/10
minutes), toutes les 30 minutes en soirée jusqu’à minuit. Après minuit et
toute la nuit, les navettes circulent à la demande, avec un numéro de
téléphone à appeler pour demander un trajet.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/mont_saint_michel_4.jpg">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2018/05/weekend_cote_emeraude/mont_saint_michel_4.jpg"
alt="Le mont Saint-Michel de nuit" />
</a>
</p>
<p>À noter aussi qu’il est très dur de manger pour un prix raisonnable sur le
mont (et en particulier le soir car les snacks ferment). Il y a le snack <a href="https://www.openstreetmap.org/node/4152080289">Au
Pélerin</a> qui propose des
sandwichs et autres snacks à des prix raisonnables, mais il est fermé le soir.
Il y a aussi un ou deux restaurants sympas, mais plutôt cher car ce sont des
restaurants de fruits de mer et de poisson. Tous les autres restaurants
forment une sorte de <em>trust</em>, sont hors de prix et à éviter (ils sont faciles
à repérer, ils ont tous la même carte avec les mêmes menus). Quand à la
célèbre <a href="https://www.openstreetmap.org/way/41676422">Mère Poulard</a>, vous
pourrez déguster une omelette pour 38€ :). Il est possible de manger pour (un
peu) moins cher en retournant <a href="https://www.openstreetmap.org/#map=17/48.61550/-1.50952">sur le
continent</a>, mais il
faut alors faire plusieurs aller-retours en navette ce qui est un peu pénible.
On avait prévu le coup et on a préféré pique-niquer sur le mont du coup, et
c’était top !</p>
<h2>Jour 3 : Dinard et retour maison</h2>
<p>Le troisième jour, on décide de passer <a href="https://www.openstreetmap.org/way/151987055#map=16/48.6207/-2.0229">le barrage sur la
Rance</a>
pour aller du côté de <a href="https://www.openstreetmap.org/relation/177066">Dinard</a>.
Le barrage abrite une usine marémotrice exploitée par <span class="caps">EDF</span>, avec un espace
découverte qui peut <a href="https://www.edf.fr/groupe-edf/producteur-industriel/energies-renouvelables/hydraulique/edf-hydraulique-bretagne-normandie/l-usine-maremotrice-de-la-rance/visiter-l-espace-decouverte">se
visiter</a>
(visite gratuite, visite guidée gratuite sur réservation). L’usine en elle-même
ne peut plus se visiter à cause de Vigipirate.</p>
<p>On a trouvé assez facilement à se garer à Dinard du côté de la <a href="https://www.openstreetmap.org/way/291977817">plage du
Prieuré</a> (mais quand on est
reparti à 15h, c’était moins évident).</p>
<p>Dinard est une grosse station balnéaire sur la côte d’Émeraude avec de grosses
villas et des hôtels de thalasso. Il y a une <a href="https://www.francedigitale.com/randonnee/afficher/309">balade en bord de
mer</a> très sympa qui
longe la côte et passe à côté des installations balnéaires des années
1920-1930 (piscines d’eau de mer, etc.), avec des panneaux explicatifs. Le
midi, on est allé à la <a href="https://www.openstreetmap.org/node/5635091376">Crêperie du
Roy</a>, qui était très bien !
Compter 15€ par personne pour galette + crêpe + boisson. L’après-midi, on
continue la balade le long de la côte, puis on est reparti pour Paris, le
week-end est fini. :(</p>
<h2>Notes</h2>
<ul>
<li>
<p>Pour vous aventurer à pied dans la baie du mont Saint-Michel, ne partez pas
sans un guide ! La liste des guides officiels est
<a href="http://www.manchetourisme.com/traversee-baie-mont-saint-michel">ici</a>. On peut
aussi traverser la baie à pied à marée basse pour rejoindre le mont (départs
depuis la côte normande), compter 15€ / personne pour le faire en petit groupe
de 20 personnes. Il y a plusieurs formules possibles, en aller-retour à pied
ou en aller simple (et éventuellement retour en bus). Par contre, traverser à
pied laisse peu de temps sur le mont (environ 1h je crois, pas assez pour voir
l’abbaye). On ne fait donc que la traversée dans la journée.</p>
</li>
<li>
<p>Pour se garer gratuitement au mont Saint-Michel, il y a moyen de se garer dans
les villages autour et de marcher (il y a <a href="https://www.openstreetmap.org/relation/3083929#map=15/48.6081/-1.5073">une promenade aménagée le long du
Couesnon</a>).
Par contre, ça veut dire marcher quelques kilomètres et de nuit, ce n’est pas
éclairé (contrairement aux parkings). L’autre solution est visiblement de
manger à la <a href="https://www.openstreetmap.org/node/2803726801">ferme du mont
Saint-Michel</a> qui vous donnera
un code pour vous garer toute la journée dans son parking.</p>
</li>
<li>
<p>Les crêperies ont toujours du bon cidre artisanal local. Par contre, très peu
ont du jus de pommes artisanal (et vous aurez bien souvent du Minute Maid à
base de concentré…). Penser à demander avant de commander du coup…</p>
</li>
<li>
<p>Quelques idées supplémentaires :
À Saint-Malo, il y a la <a href="https://www.openstreetmap.org/way/142034214">cité d’Alhet</a> qui est très sympa, avec la vue sur la Rance, l’usine marémotrice et Dinard. Il y a aussi la <a href="https://www.openstreetmap.org/node/3275333600">tour Solidor</a> (ancienne tour de garde puis prison qui abrite désormais un musée sur les marins au long cours et les cap-horniers). Il y a aussi un <a href="https://www.openstreetmap.org/way/55451125">aquarium</a>.</p>
<ul>
<li>Près de Saint-Malo, à la journée, il y a <a href="https://fr.wikipedia.org/wiki/C%C3%A9zembre">l’île de Cézembre</a> accessible <a href="http://www.compagniecorsaire.com/destinations/entry-39-ile-cezembre.html">par bateau</a>. Les horaires des bateaux obligent d’y passer une journée par contre, et il n’y a pas grand chose à faire sur l’île à part le sentier et la plage.</li>
<li>En remontant la rance, il y a plusieurs balades (et itinéraires cyclables) et <a href="https://fr.wikipedia.org/wiki/Dinan">Dinan</a>, une ville fortifiée.</li>
<li>Après Dinard, il y a <a href="https://www.openstreetmap.org/relation/145547">Saint-Lunaire</a> avec la suite du sentier côtier (le long du <span class="caps">GR34</span>), des grosses villas, des hôtels de thalasso et un golf.</li>
<li>Les plus courageux pourront pousser jusqu’au <a href="https://www.openstreetmap.org/way/135722236">Cap Fréhel</a> ou jusqu’au <a href="https://www.openstreetmap.org/way/28431246">Fort de la latte</a>.</li>
</ul>
</li>
<li>
<p>Si vous n’êtes pas en voiture, il y a de nombreux itinéraires cyclistes dans la région. Sinon, en transports en commun :</p>
<ul>
<li>Il y a des <a href="https://www.ksma.fr/se-deplacer/rechercher-un-itineraire/">bus urbains</a> pour se déplacer dans l’agglomération de Saint-Malo, jusqu’à Cancale et Dinard.</li>
<li>Il y a aussi <a href="http://www.compagniecorsaire.com/destinations/entry-41-bus-de-mer-st-malo-dinard-et-vice-versa.html">une liaison par bateau</a> entre Saint-Malo (proche intramuros, départ de la cale de Dinan) et Dinard.</li>
<li>Pour aller au Mont Saint-Michel, c’est un peu plus galère, surtout à des horaires pas très conventionnels. Il y a des <a href="https://keolis-armor.com/61-Aller-au-Mont-Saint-Michel.html">bus dédiés</a> (plutôt chers), des bus “Macron” ou le covoiturage. Une autre option semble être de rejoindre Pontorson (train ou bus) puis de Pontorson de rejoindre le mont Saint-Michel.</li>
</ul>
</li>
</ul>
<h2>Budget</h2>
<ul>
<li>Voiture : environ 100€ A/R (dont 60€ de péages). En covoiturage, il faut compter environ 25€ par personne.</li>
<li>Hébergement : 40€ / nuit pour une chambre Airbnb pour deux à Saint-Malo</li>
<li>Miam : Environ 15-20€ / personne dans une crêperie pour une galette, une crêpe et du cidre. Autour de 10€ / personne dans des snacks à emporter. Compter plutôt 20-30€ par personne pour des fruits de mer.</li>
</ul>Tracking the position of your Android phone without Google2018-01-16T18:05:00+01:002018-01-16T18:05:00+01:00Phykstag:localhost,2018-01-16:/Blog/output/2018/01/tracking-the-position-of-your-android-phone-without-google.html<p><span class="caps">TL</span>;<span class="caps">DR</span>: Use <a href="https://github.com/owntracks/android">OwnTracks</a>! Yes, even if it
is unmaintained and has anti-features! It works flawlessly with
<code>Apple UnifiedNIP</code> backend and <code>Nominatim Geocoder</code> backend (for reverse
geolocation lookup).</p>
<p>I recently moved to <a href="https://lineage.microg.org/">Lineage <span class="caps">OS</span> + microg</a> (it’s
very cool btw, it mostly works out of the box with the whole …</p><p><span class="caps">TL</span>;<span class="caps">DR</span>: Use <a href="https://github.com/owntracks/android">OwnTracks</a>! Yes, even if it
is unmaintained and has anti-features! It works flawlessly with
<code>Apple UnifiedNIP</code> backend and <code>Nominatim Geocoder</code> backend (for reverse
geolocation lookup).</p>
<p>I recently moved to <a href="https://lineage.microg.org/">Lineage <span class="caps">OS</span> + microg</a> (it’s
very cool btw, it mostly works out of the box with the whole <code>microg</code> stuff!)
on my smartphone. In parallel, I was working on
<a href="https://git.phyks.me/Phyks/infotuyo/">infotuyo</a> (think self-hosted
<a href="https://ifttt.com/"><span class="caps">IFTTT</span></a>) and home automation using
<a href="https://home-assistant.io">Home-Assistant</a>, and at some point I realized it
would be awesome if I could have an estimate of my position stored online
(where I am, with a few tens of meters precision and a few minutes resolution).</p>
<p>I know Google is offering it out of the box if you have an Android account on
your phone, but I don’t. And I don’t want anything this sensitive to be stored
on Google’s servers. So my ultimate goal is to have a selfhosted system I
control which could store my location and eventually pipe it to Home-Assistant
or infotuyo to send me reminders when I should leave for an appointment, with
itinerary, or shut power plugs at home when I leave.</p>
<h2>Server part</h2>
<p>First, I had to find a server part to handle the storage. I already had a
<a href="https://nextcloud.com/">NextCloud</a> selfhosted and I came across the
<a href="https://gitlab.com/eneiluj/phonetrack-oc">Phonetrack-<span class="caps">OC</span></a> NextCloud app.</p>
<p>It’s dumb simple (too simple sometimes) but also easy to extend. It is
compatible with most clients out there and it simply does the job, so I did
not look any further.</p>
<h2>Client part</h2>
<p>Here comes the difficult part, looking for a client to run on my Android. This
was an incredibly difficult part, in part due to limitations in Android system.</p>
<h3><code>UnifiedNIP</code> provider</h3>
<p>First, you have to choose and setup a <code>UnifiedNIP</code> provider in your <code>microg</code>
settings. I initially chose to use <code>Mozilla UnifiedNIP</code> backend to get a
network position (much faster and battery-efficient solution than <span class="caps">GPS</span>, with
good enough accuracy in Paris for this use case) and <code>Nominatim Geocoder</code>
backend for reverse geolocation (getting address from names).</p>
<p>When I got into troubles finding an app to keep track of my position, I heard
that Mozilla might be throttling calls from <code>Mozilla UnifiedNIP</code> backend, as
it can get quite heavy on their infrastructure. In the end, I decided to go
for the <code>Apple UnifiedNIP</code> backend which should not be affected by this and
tends to give better results.</p>
<h3>First try, <code>uLogger</code></h3>
<p>My first try was using
<a href="https://github.com/bfabiszewski/ulogger-android">uLogger</a> (from F-Droid). The
app had a few major issues:</p>
<ul>
<li>Sometimes it was crashing without reason (I guess it was when it could not
fetch the position, for some reason).</li>
<li>There was a setting in the app to choose which location mode one wanted to
use (<span class="caps">GPS</span> / network / balanced). The same settings is also available in the
system settings, and they had to match! That means I could not set
“balanced” in <code>uLogger</code>, hoping that it would use the best option available,
as enabled in system settings (so that if system settings is “power saving”,
it would use network and if it is “high power” it would use the <span class="caps">GPS</span>).</li>
<li>The app was logging quite erratically, throttling updates some time. I was
expecting to have a point every 5 mins but it could be one hour between two
successive points sometimes.</li>
</ul>
<p>I tried to investigate it a bit, but could not find anything to fix these
throttling issues (disabled “battery optimization” for the app without
success, etc) and did not get feedback from the Github issues.</p>
<h3>Second try, <code>traccar</code></h3>
<p><a href="https://github.com/tananaev/traccar-client-android">Traccar</a> was really
interesting as it was a free software, available on F-Droid. Additionally, it
relies on <a href="https://github.com/lostzen/lost"><span class="caps">LOST</span></a>, a replacement for Google
Play services <code>FusedLocationProvider</code> (the Android <span class="caps">API</span> to fetch user
position), written by Mapzen. It should be the perfect candidate.</p>
<p>However, same thing once again, the updates of positions were throttled and
sometimes I did not get a single point for a couple of hours. I could not find
any reason for this (not sure whether this is coming from <code>LOST</code> or
<code>traccar</code>). Moving to the next solution…</p>
<h3><code>OwnTracks</code></h3>
<p>In the end, I came across <a href="https://github.com/owntracks/android">OwnTracks</a>
which is free but not available on F-Droid as it depends on proprietary stuff
(Google Play Services and other similar libs).</p>
<p>Best way to get it is to clone the Git repository and then build the app
locally in Android Studio. I had never touched Android development before, and
it’s actually super simple to build an app from source code in Android Studio
(open the project and click “Build APKs” basically). Then, you can upload it
through “<span class="caps">USB</span> debugging” directly to your phone.</p>
<p>I followed closely the instructions in their
<a href="http://owntracks.org/booklet/features/android/">booklet</a> to maximize
performance of position tracking (basically, it boils down to disabling
“battery optimization”) and so far, for the last week, I got a point every 5
minutes or so (my update frequency) except when I could not obtain a location
for obvious reasons (subway, airplane mode). The app seems to take great care
of tracking position and is very resilient to loss of network or location.
Plus, their <a href="http://owntracks.org/booklet/">doc</a> is really well written.</p>
<p>The only downside is that I have a permanent notification on my phone now,
otherwise the app would be closed by the system. Good point is that
<code>OwnTracks</code> does not simply a dummy notification but uses it to show my
current position with reverse geolocation through Nominatim. Completely
useless, so it’s obviously a need! :)</p>
<p>So far, I sticked with <code>UnifiedNIP</code> backends and <code>OwnTracks</code> disabled from
battery optimization and a position logged every 5 mins (without any minimal
displacement) and battery usage as displayed by Android is:</p>
<ul>
<li>Around 5% for the <code>Apple UnifiedNIP</code> backend.</li>
<li>Around 2% for the <code>Nominatim Geocoder</code> backend.</li>
<li>Usage for <code>OwnTracks</code> is not displayed.</li>
</ul>
<p>To compare, my screen battery usage is almost the same as the one from <code>Apple
Unified NIP</code> and <code>Nominatim</code> is less than “sleep mode” (3%) or Whatsapp (4%).</p>
<p>Additionally, I mentioned that <code>OwnTracks</code> requires Google Play Services,
but actually it works perfectly fine with <code>microg</code>. The only downside is that
the map in the main view, showing your current position, is using Google Maps
and does not work (this panel is empty). As I only use it to log in the
background, I don’t care (and when I’m lost, I can always open <code>OsmAnd~</code> which
would fetch position faster as <code>OwnTracks</code> almost certainly requested it recently).</p>
<p>It would be super cool to see <code>OwnTracks</code> on F-Droid, but it uses non-free
features (<code>firebase-jobdispatcher</code> and Google Play Services and embed some
precompiled libraries) :/ So it’s quite a job to make it publishable on
F-Droid and sadly I don’t know enough about Android development to handle it :/</p>
<p>Hope this helps!</p>No more Velib API dump2018-01-07T18:00:00+01:002018-01-07T18:00:00+01:00Phykstag:localhost,2018-01-07:/Blog/output/2018/01/no-more-velib-api-dump.html<p>About two years ago, I decided to <a href="https://phyks.me/2015/11/velib-dataset.html">dump on a very regular
basis</a> all the available data
from the Velib <span class="caps">API</span>. Velib is the bike sharing system in Paris, and the <span class="caps">API</span>
exposes a list of stations as well as their respective occupancy (free stands,
available bikes in near realtime …</p><p>About two years ago, I decided to <a href="https://phyks.me/2015/11/velib-dataset.html">dump on a very regular
basis</a> all the available data
from the Velib <span class="caps">API</span>. Velib is the bike sharing system in Paris, and the <span class="caps">API</span>
exposes a list of stations as well as their respective occupancy (free stands,
available bikes in near realtime). I dumped the data every few minutes, and
<a href="https://pub.phyks.me/datasets/velib/">served dumps</a>.</p>
<p>However, starting from January 1st, 2018, the operator of the Velib system
changed. It used to be JCDecaux which was providing a <a href="http://developer.jcdecaux.com/">clear and comprehensive
<span class="caps">API</span></a> and is now
<a href="http://www.smovengo.fr/">Smovengo</a>, for which I could not find any opendata
endpoint at the moment.</p>
<p>Then, I keep dumping JCDecaux opendata in the dataset, but this only concerns
the few remaining stations operated by JCDecaux. All stations are expected to
be converted to the new Smovengo system by March, and there will no longer be
any data available from JCDecaux for Velib in Paris. Smovengo already has a
few operational stations, but I could not find any opendata endpoint so far
(and did not get any response from the developer contact email address), so I
cannot dump anything.</p>
<p>To sum up, Velib datasets are incomplete starting from January 1st, 2018 until
further notice… Let me know if you are aware of any way to get opendata from
Smovengo! :)</p>
<p><em>Note:</em> Smovengo is already operating bike sharing systems in other cities,
but neither
<a href="https://github.com/eskerda/pybikes/blob/master/pybikes/smoove.py">this
solution</a>
nor <a href="http://www.bicyclette-app.com/data.html">this one</a> seems to be working
for Paris. Dumping data from the <a href="https://www.velib-metropole.fr/map">official
map</a> should be possible but requires
making a lot of requests and the terms of use are unclear, so this is not
really an option. :/</p>
<p><em><span class="caps">EDIT</span>:</em> An alternative tracking service is available at <a href="http://velib.nocle.fr/">http://velib.nocle.fr/</a>. It keeps track of all the data, starting from the 8th of January, but does not offer any download option.</p>
<p><em><span class="caps">EDIT</span> 2:</em> Actually JCDecaux stopped feeding its <span class="caps">API</span>, so I no longer dump
JCDecaux data. Smovengo opendata endpoint is now available and dump should be
available again starting from the second week of January 2018.</p>
<p><em><span class="caps">EDIT</span> 3:</em> I submitted a <span class="caps">MR</span> to <a href="https://github.com/eskerda/pybikes">PyBikes</a>
and dumps of Velib data are back online!</p>Stop networking, dear Samsung TV2017-12-10T22:00:00+01:002017-12-10T22:00:00+01:00Phykstag:localhost,2017-12-10:/Blog/output/2017/12/stop-networking-dear-samsung-tv.html<p>Yesterday, I noticed some ads for upcoming Amazon Prime <span class="caps">TV</span> shows have appeared
on my Samsung “smart” <span class="caps">TV</span> (Serie 6). Apparently, they are provided by a
preinstalled app called “Tv Plus”, developped by Rakuten Group and which I
cannot uninstall. I cannot uninstall other preinstalled apps as well, such as …</p><p>Yesterday, I noticed some ads for upcoming Amazon Prime <span class="caps">TV</span> shows have appeared
on my Samsung “smart” <span class="caps">TV</span> (Serie 6). Apparently, they are provided by a
preinstalled app called “Tv Plus”, developped by Rakuten Group and which I
cannot uninstall. I cannot uninstall other preinstalled apps as well, such as Netflix.</p>
<p>I really don’t like paying an expensive smart <span class="caps">TV</span> and getting ads on it, so I
investigated it a bit, trying to find a way to shut them down. Here are my findings.</p>
<p>First idea was to simply run <a href="http://mitmproxy.org/">mitmproxy</a> on my laptop
and find what was going on on the <span class="caps">TV</span>. Unfortunately, no matter how smart the
<span class="caps">TV</span> is, there is no way to set some proxy settings, and I did not want to look
for a workaround for too long. Then, I simply connected my <span class="caps">TV</span> to my Ethernet
port on my laptop and created a bridge with Wifi interface to monitor what was
going on with <a href="https://www.wireshark.org/">Wireshark</a>, using <a href="https://zerobin.net/?71b7392407325431#8zpPOvEW0K/gOW7S27Nka8uyW5IAymBhJDsfKB+lNkE=">this
script</a>.</p>
<p>I discovered that, even when the <span class="caps">TV</span> was shutdown (or at least seemed to be),
it was making several queries per minute to a bunch of servers! Here is a
quick list of servers contacted at least once per minute for about 15 mins:</p>
<div class="highlight"><pre><span></span><code>ads.samsungads.com
samsungads.com
gpm.samsungqbe.com
osb.samsungqbe.com
osb-apps.samsungqbe.com
osb-eusvc.samsungqbe.com
cdn.samsungcloudsolution.com
musicid.samsungcloudsolution.com
notice.samsungcloudsolution.com
noticecdn.samsungcloudsolution.com
time.samsungcloudsolution.com
lcprd2.samsungcloudsolution.net
configprd.samsungcloudsolution.net
otnprd8.samsungcloudsolution.net
otnprd9.samsungcloudsolution.net
otn.samsungcloudcdn.com
samsungotn.net
www.samsungotn.net
prod-kami.wuaki.tv
prod-tvplus-pmd.akamai.cdn.wuaki.tv
netflix.com
api-global.geo.netflix.com
many other *.netflix.com
</code></pre></div>
<p>Wow, that’s a lot! Besides samsung domains, it contacts <code>netflix.com</code> at least
once per minute (<span class="caps">WTF</span>, I don’t even have a Netflix account…) and <code>wuaki.tv</code>
which is owned by Rakuten Group.</p>
<p>Then, I set up my local resolver to resolve all these domains to <code>127.0.0.1</code>,
and the ads went away! Or so I thought…</p>
<p>Two major things happened at this point:
1. First, the <span class="caps">TV</span> started contacting <code>log-ingestion-eu.samsungacr.com</code>,
probably some crash-reporting endpoint to notify Samsung about not being
able to contact other domains anymore. That’s not a big deal, one should
just include it as well in the local resolver config.
2. Second, and more concerning, the <span class="caps">TV</span> started contacting <code>8.8.8.8</code> (yes,
Google Public <span class="caps">DNS</span>…) because I was blocking requests through my <span class="caps">DNS</span>
resolver. This seems to be hardcoded and to be a fallback whenever the <span class="caps">DNS</span>
resolver is not responding what the <span class="caps">TV</span> expects.</p>
<p>My <span class="caps">ISP</span> router (Freebox Mini) does not let me add static routes to block
<code>8.8.8.8</code>. The <span class="caps">TV</span> is behing an OpenWRT bridge (without routing as it is a pity
to configure to let <span class="caps">DLNA</span> pass through), and bridges can’t filter out at L3
level (apparently, it could be possible with <code>ebtables</code>, but I could not get
it working).</p>
<p>In the end, a quick and dirty solution was to make the local resolver return
an <span class="caps">IP</span> address of a local webserver I control and would answer any requests,
and the number of <span class="caps">DNS</span> queries to <code>8.8.8.8</code> dropped. That’s not perfect and it
still makes some queries, but at least I no longer have ads.</p>
<p>Finally, the <span class="caps">TL</span>,<span class="caps">DR</span> is:
* Your Samsung <span class="caps">TV</span> is contacting a <span class="caps">LOT</span> of domains, even when it is offline.
* My Unbound config which helped me get rid of the ads is:</p>
<div class="highlight"><pre><span></span><code>#<span class="w"> </span><span class="nv">TV</span><span class="w"> </span><span class="nv">starts</span><span class="w"> </span><span class="nv">querying</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">eth0</span><span class="w"> </span><span class="nv">domain</span>,<span class="w"> </span><span class="nv">WTF</span>?<span class="w"> </span><span class="nv">This</span><span class="w"> </span><span class="nv">is</span><span class="w"> </span><span class="nv">just</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">prevent</span><span class="w"> </span><span class="nv">unnecessary</span>
#<span class="w"> </span><span class="nv">traffic</span><span class="w"> </span><span class="nv">upstream</span>.
<span class="nv">local</span><span class="o">-</span><span class="nv">zone</span>:<span class="w"> </span><span class="s2">"eth0"</span><span class="w"> </span><span class="nv">redirect</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"eth0 86400 IN AAAA ::1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">zone</span>:<span class="w"> </span><span class="s2">"samsungads.com"</span><span class="w"> </span><span class="nv">redirect</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungads.com 86400 IN A 192.168.0.1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungads.com 86400 IN AAAA ::1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">zone</span>:<span class="w"> </span><span class="s2">"samsungqbe.com"</span><span class="w"> </span><span class="nv">redirect</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungqbe.com 86400 IN A 192.168.0.1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungqbe.com 86400 IN AAAA ::1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">zone</span>:<span class="w"> </span><span class="s2">"samsungacr.com"</span><span class="w"> </span><span class="nv">redirect</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungacr.com 86400 IN A 192.168.0.1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungacr.com 86400 IN AAAA ::1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">zone</span>:<span class="w"> </span><span class="s2">"samsungcloudsolution.com"</span><span class="w"> </span><span class="nv">redirect</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungcloudsolution.com 86400 IN A 192.168.0.1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungcloudsolution.com 86400 IN AAAA ::1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">zone</span>:<span class="w"> </span><span class="s2">"samsungcloudsolution.net"</span><span class="w"> </span><span class="nv">redirect</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungcloudsolution.net 86400 IN A 192.168.0.1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungcloudsolution.net 86400 IN AAAA ::1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">zone</span>:<span class="w"> </span><span class="s2">"samsungcloudcdn.com"</span><span class="w"> </span><span class="nv">redirect</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungcloudcdn.com 86400 IN A 192.168.0.1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungcloudcdn.com 86400 IN AAAA ::1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">zone</span>:<span class="w"> </span><span class="s2">"samsungotn.net"</span><span class="w"> </span><span class="nv">redirect</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungotn.net 86400 IN A 192.168.0.1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"samsungotn.net 86400 IN AAAA ::1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">zone</span>:<span class="w"> </span><span class="s2">"wuaki.tv"</span><span class="w"> </span><span class="nv">redirect</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"wuaki.tv 86400 IN A 192.168.0.1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"wuaki.tv 86400 IN AAAA ::1"</span>
#<span class="w"> </span><span class="nv">This</span><span class="w"> </span><span class="nv">trick</span><span class="w"> </span><span class="nv">with</span><span class="w"> </span><span class="nv">TV_IP</span><span class="w"> </span><span class="nv">and</span><span class="w"> </span><span class="nv">local</span><span class="o">-</span><span class="nv">zone</span><span class="o">-</span><span class="nv">override</span><span class="w"> </span><span class="nv">is</span><span class="w"> </span><span class="nv">here</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">block</span><span class="w"> </span><span class="nv">Netflix</span><span class="w"> </span><span class="nv">only</span>
#<span class="w"> </span><span class="nv">on</span><span class="w"> </span><span class="nv">TV</span>,<span class="w"> </span><span class="nv">in</span><span class="w"> </span><span class="nv">case</span><span class="w"> </span><span class="nv">other</span><span class="w"> </span><span class="nv">computers</span><span class="w"> </span><span class="nv">on</span><span class="w"> </span><span class="nv">my</span><span class="w"> </span><span class="nv">network</span><span class="w"> </span><span class="nv">want</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">use</span><span class="w"> </span><span class="nv">Netflix</span>.<span class="w"> </span><span class="nv">TV</span><span class="w"> </span><span class="nv">has</span><span class="w"> </span><span class="nv">to</span>
#<span class="w"> </span><span class="nv">get</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">static</span><span class="w"> </span><span class="nv">DHCP</span><span class="w"> </span><span class="nv">lease</span>.
<span class="nv">local</span><span class="o">-</span><span class="nv">zone</span>:<span class="w"> </span><span class="s2">"netflix.com"</span><span class="w"> </span><span class="nv">always_transparent</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"netflix.com 86400 IN A 192.168.0.1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">data</span>:<span class="w"> </span><span class="s2">"netflix.com 86400 IN AAAA ::1"</span>
<span class="nv">local</span><span class="o">-</span><span class="nv">zone</span><span class="o">-</span><span class="nv">override</span>:<span class="w"> </span><span class="s2">"netflix.com"</span><span class="w"> </span><span class="nv">TV_IP</span><span class="w"> </span><span class="nv">redirect</span>
</code></pre></div>
<p>where <code>192.168.0.1</code> is a webserver answering any request.</p>
<ul>
<li>It still makes some <span class="caps">API</span> calls to Samsung domains, by resolving through
<code>8.8.8.8</code>, but it is a pity to block in my setup. If you happen to have some
ideas, I’m really interested! (Or I might simply buy a router…)</li>
</ul>
<p><em>Note:</em> Of course, one of the obvious thing to do would be to simply not
connect the <span class="caps">TV</span> to the network. But then, there is no point in having a smart
<span class="caps">TV</span>… (and stuff such as UPnP/<span class="caps">DLNA</span> streaming are very convenient, I don’t want
to loose it). Other option would be to simply let it access the local network
and not the internet, but my boyfriend sometimes watches Youtube and web
services directly on the <span class="caps">TV</span>, so whatever solution I could come up with should
leave these features intact.</p>
<p><em>Note:</em> These <span class="caps">API</span> calls made by the <span class="caps">TV</span> might be legit. Still, blocking them
did not result in any loss of functionnality so far (besides maybe
auto-update). They are all encrypted and I did not set up a <code>mitmproxy</code> to
check what actual data was sent. If anyone has a simple idea to set it quickly
when the other device don’t let us set proxy settings, I’m more than
interested :)</p>
<p><strong>Update:</strong> I tried to sniff the queries with <code>mitmproxy</code> used as a
transparent proxy, but there is no way to make the <span class="caps">TV</span> trust <code>mitmproxy</code>
certificate, then it does not seem to be feasible (<span class="caps">TV</span> drops connections when
it realizes that the certificate is invalid).</p>
<p><strong>Update:</strong> Actually it is quite simple to set up an OpenWRT to let it pass
<span class="caps">DLNA</span> content from <span class="caps">WAN</span> to <span class="caps">LAN</span> (see the
<a href="https://wiki.openwrt.org/doc/howto/udp_multicast#igmp_proxy">wiki</a>).
Basically, you have to install <code>kmod-bridge</code>, <code>igmpproxy</code> and follow the wiki
part on <code>igmpproxy</code> to set it. Don’t forget to disable <code>multicast_snooping</code> if
you want WiFi clients from your router to be able to broadcast to wired
clients (otherwise only wired clients can stream apparently). In the end, it
works great and I can isolate the <span class="caps">TV</span> :) Then, it is better to simply use
<code>127.0.0.1</code> rather than redirecting to a catchall webserver.</p>
<p><strong>Update:</strong> I discovered that actually the apps on the <span class="caps">TV</span> can run in
background, and it appears there is no way to close them. Then, if you open
Netflix once, even without connecting, the Netflix app will stay in background
and it is the reason why I had so many requests to Netflix. It seems that
after some time the app will close and the <span class="caps">TV</span> will no longer make such requests.</p>Dons des mois d’octobre et novembre2017-12-04T21:10:00+01:002017-12-04T21:10:00+01:00Phykstag:localhost,2017-12-04:/Blog/output/2017/12/dons-des-mois-doctobre-et-novembre.html<p>Pour le mois d’octobre, j’ai fait un don de 10€ à
<a href="https://github.com/singapore/renovate">Renovate</a>, un super script à héberger
soi-même pour ouvrir automatiquement des fusiodemandes pour vos dépendances
NodeJS, à la <a href="http://greenkeeper.io/">GreenKeeper.io</a>. En plus, ça peut
tourner en quelques clics sur un Heroku gratuit, et ça supporte à la …</p><p>Pour le mois d’octobre, j’ai fait un don de 10€ à
<a href="https://github.com/singapore/renovate">Renovate</a>, un super script à héberger
soi-même pour ouvrir automatiquement des fusiodemandes pour vos dépendances
NodeJS, à la <a href="http://greenkeeper.io/">GreenKeeper.io</a>. En plus, ça peut
tourner en quelques clics sur un Heroku gratuit, et ça supporte à la fois
Github et Gitlab. Et le support est top :)</p>
<p>Pour le mois de novembre, j’ai fait un don de 10€ pour <a href="https://exodus-privacy.eu.org//">Exodus
Privacy</a>, une association qui génère des
<a href="https://reports.exodus-privacy.eu.org/reports/apps/">rapports</a> des
permissions demandées et des <em>trackers</em> publicitaires identifiés dans les
applications Android, pour faire suite aux récentes <a href="http://www.numerama.com/politique/282934-enquete-comment-les-apps-figaro-lequipe-ou-closer-participent-au-pistage-de-10-millions-de-francais.html">révélations de
Numerama</a>.
Ils analysent de nouvelles applications chaque jour (déjà plus de 400
actuellement !).</p>10 jours au Canada2017-11-19T11:53:00+01:002017-11-19T11:53:00+01:00Phykstag:localhost,2017-11-19:/Blog/output/2017/11/10-jours-au-canada.html<p>Voici quelques notes sur notre <em>roadtrip</em> de 10 jours dans le nord-est des
États-Unis et au Canada l’an dernier. On était parti mi-octobre, peut-être un
poil trop tard pour avoir toutes les couleurs sur les arbres pendant l’été
indien (les couleurs étaient top au début de la semaine …</p><p>Voici quelques notes sur notre <em>roadtrip</em> de 10 jours dans le nord-est des
États-Unis et au Canada l’an dernier. On était parti mi-octobre, peut-être un
poil trop tard pour avoir toutes les couleurs sur les arbres pendant l’été
indien (les couleurs étaient top au début de la semaine, mais les feuilles
sont tombées assez vite pendant la semaine, surtout en montant vers le nord).</p>
<h2>Jour 0: Aller à Niagara Falls (650km, 7h)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=41.364442&n2=-75.492554&n3=7&a=41.308658,-72.925297,43.093352,-79.070631&b=0&c=1&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/canada_jour_0.png" alt="Itinéraire jour 0"/>
</a>
</p>
<p>Départ un vendredi en fin d’après-midi de New Haven, on file vers <a href="https://fr.wikipedia.org/wiki/Niagara_Falls_(Ontario)">Niagara
Falls</a>, la ville au
Canada juste à côté des <a href="https://fr.wikipedia.org/wiki/Chutes_du_Niagara">chutes du
Niagara</a>. La plupart des
hôtels sont du côté canadien et il vaut donc mieux aller de ce côté-ci, au
moins on ne voit pas des hôtels et attractions touristiques en regardant les
chutes (vu qu’ils sont dans notre dos :) !</p>
<p>On arrive dans la soirée à notre motel, l’<a href="https://www.booking.com/hotel/ca/america-s-best-inn-amp-suites.fr.html">America’s Hospitality
Inn</a>,
un peu excentré mais vraiment top et pas cher ! Ne pas oublier d’aller voir
les chutes le soir, car elles sont
<a href="https://www.niagaraparks.com/events/event/falls-illumination/">illuminées</a> !</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=41.364442&n2=-75.492554&n3=7&a=41.308658,-72.925297,43.093352,-79.070631&b=0&c=1&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 1: Niagara Falls et Toronto (150km, 2h)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=43.158111&n2=-78.940887&n3=9&a=43.093352,-79.070631,43.113735,-79.062316,43.12899,-79.060535,43.147842,-79.045258,43.241701,-79.06105,43.252705,-79.131775,43.666009,-79.406948&b=0&c=1&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/canada_jour_1.png" alt="Itinéraire jour 1"/>
</a>
</p>
<p>Premier jour de ce voyage, aux <a href="https://fr.wikipedia.org/wiki/Chutes_du_Niagara">chutes du
Niagara</a>, en commençant par
une promenade en haut des chutes, du côté canadien. On peut se garer assez
facilement dans le centre de Niagara Falls, qui n’est pas très loin, pour
moins de 10$ la journée.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC01909.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC01909.JPG" alt="Chutes du Niagara"/>
</a>
</p>
<p>Il y a de <a href="https://www.niagarafallstourism.com/play/falls-experiences/">nombreuses
attractions</a>
liées aux chutes, souvent assez chères. On ne savait pas trop laquelle
choisir, et finalement quelqu’un nous a donné deux tickets pour
<a href="https://www.niagarafallstourism.com/play/falls-experiences/hornblower-niagara-cruises-in-niagara-falls/">Voyage to the
falls</a>,
un bateau qui emmène tout près des chutes. C’était top !</p>
<p>On part ensuite direction Toronto en suivant la rivière Niagara, jusqu’à
<a href="http://www.openstreetmap.org/node/1829283475">Niagara-on-the-Lake</a>. On
s’arrête en route aux nombreux points de vue, notamment celui à côté de la
<a href="http://www.openstreetmap.org/way/87441146">Whirlpool Aero Car</a>.</p>
<p>Il y a des balades très sympas (et des blocs pour faire de l’escalade) dans le
<a href="http://www.openstreetmap.org/way/158461048">Niagara Glen Nature Reserve</a>.
Penser à bien prendre en photo la
<a href="https://www.niagaraparks.com/media/2017/07/Niagara-Glen-Trail-Map-2017.pdf">carte</a>
au départ des sentiers, ça évite de tourner en rond après :)</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02082.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02082.JPG" alt="Niagara Glen"/>
</a>
</p>
<p>On arrive à <a href="https://fr.wikipedia.org/wiki/Toronto">Toronto</a> en fin
d’après-midi. Le parking est assez simple en centre-ville, mais il faut faire
très attention à bien déchiffrer les nombreux panneaux d’exceptions au
stationnement autorisé. On fait un tour dans le centre-ville (le Financial
District et ses gratte-ciels), puis on va voir le coucher de soleil sur les
quais. On peut monter en haut de la <a href="https://fr.wikipedia.org/wiki/Tour_CN">tour
<span class="caps">CN</span></a>, un des bâtiments les plus hauts
sur Terre, qui en plus possède un plancher de verre en haut, à 342m du sol.
L’entrée est assez chère ($36 <span class="caps">CDN</span>) et il y a beaucoup de queue.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02096.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02096.JPG" alt="Tour CN"/>
</a>
</p>
<p>On va dormir dans un Airbnb à Mississauga, à un quart d’heure de Toronto.</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=43.158111&n2=-78.940887&n3=9&a=43.093352,-79.070631,43.113735,-79.062316,43.12899,-79.060535,43.147842,-79.045258,43.241701,-79.06105,43.252705,-79.131775,43.666009,-79.406948&b=0&c=1&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 2: Kingston et Ottawa (480km, 5h)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=44.37295&n2=-77.313538&n3=8&a=43.570452,-79.626636,44.229883,-76.480349,44.231225,-76.460745,44.791582,-75.51178,45.423309,-75.698306,45.427562,-75.692691&b=0&c=1&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/canada_jour_2.png" alt="Itinéraire jour 2"/>
</a>
</p>
<p>On repart le lendemain matin, direction
<a href="https://fr.wikipedia.org/wiki/Ottawa">Ottawa</a>, la capitale. En route, on
s’arrête à <a href="https://fr.wikipedia.org/wiki/Kingston_(Ontario)">Kingston</a>, la
première capitale du Canada.</p>
<p>Pas de chance, il ne fait pas beau. On arrive quand même à faire un tour en
centre-ville et à aller voir le point de vue sur la ville depuis <a href="https://fr.wikipedia.org/wiki/Fort_Henry_(Canada)">Fort
Henry</a>, entre deux ondées.
Une liste de choses à voir à Kingston est disponible
<a href="https://fr.wikivoyage.org/wiki/Kingston_(Ontario)#Voir">ici</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02124.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02124.JPG" alt="Kingston"/>
</a>
</p>
<p>On continue sur la route 2 quasiment jusqu’à route 416 pour Ottawa, ce qui
nous permet de longer le lac Ontario puis le fleuve Saint-Laurent et de
s’arrêter régulièrement prendre des photos entre deux averses :)</p>
<p>Le soir, on fait une petite balade à pied dans Ottawa, en passant à <a href="https://fr.wikipedia.org/wiki/Colline_du_Parlement">la
colline du parlement</a>
(magnifique de nuit) et au <a href="https://en.wikipedia.org/wiki/ByWard_Market">Marché
By</a>. Et on mange au
<a href="http://www.restaurant18.com/">e18hteen</a>, un restaurant plutôt classe et un
peu cher, mais les plats sont vraiment délicieux.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02144.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02144.JPG" alt="Colline du parlement"/>
</a>
</p>
<p>On dort le soir à Ottawa, dans un Airbnb dans <a href="https://en.wikipedia.org/wiki/ByWard_Market">ByWard
Market</a>, près du centre-ville et
permettant donc de tout visiter à pied.</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=44.37295&n2=-77.313538&n3=8&a=43.570452,-79.626636,44.229883,-76.480349,44.231225,-76.460745,44.791582,-75.51178,45.423309,-75.698306,45.427562,-75.692691&b=0&c=1&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 3: De Ottawa à Montréal (200km, 2h)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=45.32222&n2=-74.560089&n3=9&a=45.427562,-75.692691,45.682817,-74.944139,45.556808,-73.556393,45.531567,-73.597408&b=0&c=1&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/canada_jour_3.png" alt="Itinéraire jour 3"/>
</a>
</p>
<p>Le matin, on refait un petit tour à Ottawa, l’occasion de voir la ville de
jour et sous le soleil. On passe voir le <a href="https://www.gallery.ca/">musée des beaux-arts du
Canada</a>, les
<a href="http://www.pc.gc.ca/fr/docs/r/on/rideau/whl-lhm/chap2/chap2A1/chap2A1a">écluses</a>
sur le canal Rideau, la colline du parlement. On fait une visite guidée du
Parlement, très intéressante et instructive !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02174.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02174.JPG" alt="Écluses"/>
</a>
</p>
<p>On part ensuite direction <a href="http://parcomega.ca/">le Parc Oméga</a>, un parc
animalier à mi-chemin entre Ottawa et Montréal. Tout le parcours dans le parc
se fait en voiture, un peu comme un safari, en écoutant une station de radio
locale pour avoir des informations sur les animaux. La plupart des animaux
sont en liberté et on croise tout le bestiaire du Canada, des rennes aux bisons.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02229.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02229.JPG" alt="Parc Oméga"/>
</a>
</p>
<p>On arrive dans la soirée à notre Airbnb dans le quartier de <a href="https://fr.wikipedia.org/wiki/La_Petite-Patrie_(quartier)">La
Petite-Patrie</a> à
Montréal. En arrivant, notre hôte nous file un super conseil pour la soirée :
en septembre et en octobre, le jardin botanique de Montréal <a href="http://calendrier.espacepourlavie.ca/jardins-de-lumiere">se couvre de
lampions chinois et
japonais</a> et c’est
vraiment magnifique !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02271.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02271.JPG" alt="Jardins de lumière"/>
</a>
</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=45.32222&n2=-74.560089&n3=9&a=45.427562,-75.692691,45.682817,-74.944139,45.556808,-73.556393,45.531567,-73.597408&b=0&c=1&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 4: Montréal</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=45.512512&n2=-73.571877&n3=14&a=45.531567,-73.597408,45.50393,-73.587549,45.525274,-73.574666,45.518196,-73.556385,45.509369,-73.564174,45.510588,-73.550313,45.504892,-73.557678,45.531567,-73.597408&b=2&c=1&g1=-1&g2=0&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/canada_jour_4.png" alt="Itinéraire jour 4"/>
</a>
</p>
<p>On part le matin direction le
<a href="https://fr.wikipedia.org/wiki/Mont_Royal">Mont-Royal</a> (qui est beaucoup plus
haut que ce qu’on avait prévu) pour profiter de la vue sur la ville depuis le
<a href="https://fr.wikipedia.org/wiki/Chalet_du_Mont-Royal">chalet</a> au sommet. En y
allant, on traverse le quartier du
<a href="https://fr.wikipedia.org/wiki/Le_Plateau-Mont-Royal">Plateau-Mont-Royal</a>,
tantôt ressemblant à Brooklyn, tantôt avec des rues résidentielles typiques et
ses maisons avec les escaliers en façade.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02303.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02303.JPG" alt="Mont-Royal"/>
</a>
</p>
<p>Il y avait des travaux sur les chemins qui redescendaient sur le centre-ville,
donc a été obligé de redescendre sur le Plateau, juste à temps pour prendre
une <a href="https://fr.wikipedia.org/wiki/Poutine_(plat)">poutine</a> à <a href="http://labanquise.com/">La
Banquise</a> (visiblement un des meilleurs endroits pour
prendre une poutine) et magasiner un peu.</p>
<p>L’après-midi, on repart direction le centre-ville, en passant par <a href="https://fr.wikipedia.org/wiki/Village_gai_(Montr%C3%A9al)">le
Village</a>, le
quartier gay de Montréal (et l’un des plus grands au monde). On remonte
ensuite la <a href="https://fr.wikipedia.org/wiki/Rue_Sainte-Catherine_(Montr%C3%A9al)">rue
Sainte-Catherine</a>
et on fait un <a href="http://www.vieux.montreal.qc.ca/tour/0carte.htm">tour dans le vieux
Montréal</a> et sur les quais.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02376.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02376.JPG" alt="Montréal"/>
</a>
</p>
<p>On finit par plonger dans le <a href="https://fr.wikipedia.org/wiki/Montr%C3%A9al_souterrain">Montréal
souterrain</a>, ce réseau
de 33 kilomètres de tunnels qui court sous la ville, avant de prendre le métro
pour rentrer.</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=45.512512&n2=-73.571877&n3=14&a=45.531567,-73.597408,45.50393,-73.587549,45.525274,-73.574666,45.518196,-73.556385,45.509369,-73.564174,45.510588,-73.550313,45.504892,-73.557678,45.531567,-73.597408&b=2&c=1&g1=-1&g2=0&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 5: Parc naturel de la Jacques-Cartier et Québec (340km, 3h40)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=46.67771&n2=-71.062317&n3=8&a=45.531567,-73.597408,47.211508,-71.397008,46.858563,-71.262817&b=0&c=1&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/canada_jour_5.png" alt="Itinéraire jour 5"/>
</a>
</p>
<p>La météo n’étant pas franchement optimiste pour les jours suivants, on décide
d’inverser les deux jours prévus, et de faire un peu plus de route que prévu
aujourd’hui, pour aller au <a href="https://www.sepaq.com/pq/jac/">parc naturel de la
Jacques-Cartier</a>, un grand parc national à
quelques dizaines de kilomètres au nord de Québec, dans la vallée de la
rivière Jacques-Cartier.</p>
<p>Le parc est immense et on finit par se décider pour le <a href="http://trekking-quebec.com/blog/sports/randonnee/les-loups-2/">sentier des
Loups</a>, sur les
conseils d’un <em>ranger</em>. Le sentier est magnifique, on commence sous les bois
puis on monte jusqu’au point de vue sur la vallée. Le ciel s’est même dégagé
en fin d’après-midi ! Seul regret, on y était un petit peu tard dans le mois
d’octobre, et les arbres avaient en partie perdu leurs feuilles.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02413.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02413.JPG" alt="Sentier des Loups"/>
</a>
</p>
<p>Au retour, on profite des quelques rayons de soleil pour aller voir la
Jacques-Cartier de près (<em>spoiler:</em> l’eau était glacée). La nuit commençant à
tomber, on part en direction de notre Airbnb pour les prochains jours, à
Québec, juste à temps avant la pluie.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02635.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02635.JPG" alt="Parc naturel de la Jacques-Cartier"/>
</a>
</p>
<p>Le soir, on profite d’une accalmie pour sortir faire un tour dans le Québec de
nuit, qui ressemble beaucoup à Saint-Malo. Après quelques semaines en
Amérique, on est surpris de trouver ces rues tortueuses et ces vieux
bâtiments ! C’est quasiment impossible de se garer dans la vieille-ville
entourée des remparts donc il vaut mieux se garer en extérieur et marcher un peu.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02659.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02659.JPG" alt="Vieux Québec"/>
</a>
</p>
<p>On fait un gros tour en passant les remparts, en se baladant dans le vieux
centre-ville puis en allant dans le quartier du Petit-Champlain, en contrebas
de la vielle-ville. On mange au <a href="http://www.lapinsaute.com/francais/accueil/">Lapin
Sauté</a>, un restaurant français
vraiment top, puis on remonte sur les <a href="http://www.openstreetmap.org/way/105924801">terrasses
Dufferin</a> et en direction de la citadelle.</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=46.67771&n2=-71.062317&n3=8&a=45.531567,-73.597408,47.211508,-71.397008,46.858563,-71.262817&b=0&c=1&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 6: Autour de Québec (60km, 1h30)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=46.829546&n2=-71.213207&n3=12&a=46.837004,-71.219301,46.868554,-71.365385,46.88482,-71.144811,46.891417,-71.149294,46.889058,-71.072273,46.812162,-71.213636&b=0&c=1&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/canada_jour_6.png" alt="Itinéraire jour 6"/>
</a>
</p>
<p>Pour ce sixième jour, on commence par aller faire un tour autour de la ville
de Québec. On va visiter <a href="http://tourismewendake.ca/fr/accueil/">Wendake</a>, une
réserve Huronne-Wendat. On en apprend beaucoup sur le fonctionnement des
réserves, l’autonomie que le gouvernement leur accorde (ils ont leur propre
école, leur propre police, etc.) et l’impact de la colonisation européenne.</p>
<p>On s’arrête ensuite aux <a href="https://www.sepaq.com/ct/pcm/">Chutes Montmorency</a>,
d’impressionnantes chutes, encore plus hautes que celles de Niagara ! On peut
s’arrêter gratuitement en bas des chutes et il y a un parc national en haut
des chutes. Seul le stationnement est payant au parc national, mais le
quartier étant résidentiel, il est possible de se garer gratuitement dans le
quartier et de marcher un peu.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02737.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02737.JPG" alt="Chutes Montmorency"/>
</a>
</p>
<p>On traverse ensuite le pont au-dessus du Saint-Laurent qui mène à <a href="https://fr.wikipedia.org/wiki/%C3%8Ele_d%27Orl%C3%A9ans">l’île
d’Orléans</a> et on
roule quelques kilomètres sur l’île jusqu’à
<a href="https://fr.wikipedia.org/wiki/Saint-Pierre-de-l%27%C3%8Ele-d%27Orl%C3%A9ans">Saint-Pierre</a>.</p>
<p>À ce moment, on hésite beaucoup entre continuer à remonter le Saint-Laurent
jusqu’à
<a href="http://www.parcsregionaux.org/parcs-regionaux/parcs/parc-regional-des-sept-chutes/">Sept-Chutes</a>
voire jusqu’à <a href="https://fr.wikipedia.org/wiki/Saguenay_(ville)">Saguenay</a>, mais
c’est assez long et le temps se couvre. Retour vers le centre-ville de Québec
du coup.</p>
<p>Finalement, il fait beau à Québec et on refait un tour dans le vieux Québec,
de jour cette fois. Le soir, on mange au <a href="http://lebureaudeposte.com/?page_id=2">Bureau de
Poste</a>, un super bar avec un menu
(burgers, poutines, etc.) à prix unique et une bonne ambiance !</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=46.829546&n2=-71.213207&n3=12&a=46.837004,-71.219301,46.868554,-71.365385,46.88482,-71.144811,46.891417,-71.149294,46.889058,-71.072273,46.812162,-71.213636&b=0&c=1&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 7: Salem (650km, 6h15)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=44.727223&n2=-67.81311&n3=7&a=46.858563,-71.262817,44.097115,-71.679977,42.52191,-70.892045&b=0&c=1&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/canada_jour_7.png" alt="Itinéraire jour 7"/>
</a>
</p>
<p>Départ pour <a href="https://fr.wikipedia.org/wiki/Salem_(Massachusetts)">Salem</a> le
matin, et pas mal de route devant nous. Il fait moche (en fait, ça sera notre
seul jour de grosse pluie vraiment bloquante de la semaine) et tant mieux, car
c’est une journée “voiture”.</p>
<p>On avait prévu de s’arrêter en route à <a href="https://www.nhstateparks.org/visit/state-parks/flume-gorge.aspx">Flume
Gorge</a>. On y
est passé et ça avait l’air très joli. On n’a pas fait la visite complète car
il pleuvait trop et on a préféré passer plus de temps à Salem du coup.</p>
<p>Le soir, on arrive à Salem, une ville connue pour <a href="https://fr.wikipedia.org/wiki/Sorci%C3%A8res_de_Salem">la chasse aux
sorcières</a> et avec tout
un folklore “paranormal” autour. On a fait un premier tour à pied dans le
vieux Salem, en suivant <a href="http://salem.org/listing/salem-heritage-trail/">la ligne
rouge</a> tracée au sol et qui
fait le tour de la ville. À la nuit tombée, avec le temps pluvieux et
Halloween proche, la ville a une ambiance très particulière et on se lance
tenter par <a href="http://www.salemghosttours.com/">une visite guidée de la ville et de ses
fantômes</a>.</p>
<p>On a mangé au <a href="http://www.bostonhotdog.co/">Boston Hot Dog Company</a>, qui fait
des hot dogs sympas.</p>
<p>Le soir, on dort dans Salem dans un Airbnb pas top et un peu éloigné du
centre, mais c’est tout ce qu’on avait trouvé :/</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=44.727223&n2=-67.81311&n3=7&a=46.858563,-71.262817,44.097115,-71.679977,42.52191,-70.892045&b=0&c=1&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 8: Boston (100km, 1h30)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=42.268671&n2=-70.587845&n3=10&a=42.509276,-70.902952,42.357529,-71.051502,41.974796,-70.973359&b=2&c=1&g1=-1&g2=0&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/canada_jour_8.png" alt="Itinéraire jour 8"/>
</a>
</p>
<p>Le lendemain, départ pour <a href="https://fr.wikipedia.org/wiki/Boston">Boston</a>.
Première question : où garer notre voiture à proximité du centre-ville, et à
un tarif raisonnable (et pas à 10$ la demi-heure) ? Finalement, on a beaucoup
de chance, et on est un samedi. Le samedi, certains parkings proposent un
tarif fixe à la journée, très raisonnable. On s’est garé à l’<a href="https://bostonparking.spplus.com/boston-1-international-place-parking.html">International
Place
Parking</a>,
plutôt bien situé, et à 10$ la journée le weekend.</p>
<p>Le plus simple pour se balader à Boston est sûrement de suivre la <a href="http://www.thefreedomtrail.org/">Freedom
Trail</a>, cette ligne rouge qui passe devant
les principaux monuments historiques du centre-ville et finit au <a href="https://www.nps.gov/bost/learn/historyculture/bhm.htm">Bunker Hill
monument</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02808.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02808.JPG" alt="Massachusetts State House"/>
</a>
</p>
<p>Ensuite, retour à <a href="https://www.faneuilhallmarketplace.com/">Faneuil Hall
Marketplace</a> pour manger (un
<a href="https://en.wikipedia.org/wiki/Lobster_roll"><em>lobster roll</em></a> typique).</p>
<p>L’après-midi, direction le
<a href="https://fr.wikipedia.org/wiki/Massachusetts_Institute_of_Technology"><span class="caps">MIT</span></a> où
on retrouve un ami qui nous fait visiter le campus, ainsi que celui
d’<a href="https://fr.wikipedia.org/wiki/Universit%C3%A9_Harvard">Harvard</a> tout près.
On prend des gaufres chez <a href="http://zinnekenswaffles.com/">Zinneken’s</a> pour le
goûter et on se croit revenu en Europe :)</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02877.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02877.JPG" alt="MIT"/>
</a>
</p>
<p>On repart ensuite à pied en direction de la <a href="https://fr.wikipedia.org/wiki/Prudential_Tower">Prudential
Tower</a>, ce qui nous permet
d’admirer la vue sur la ville en passant sur le pont sur la rivière Charles.
Le <a href="http://skywalkboston.com/">Skywalk Observatory</a> n’est sûrement pas le
gratte-ciel le plus impressionnant, mais il est à un tarif très abordable, et
la vue d’en-haut sur Boston de nuit est superbe.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02889.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02889.JPG" alt="Skywalk Observatory"/>
</a>
</p>
<p>Finalement, on mange (trop) au <a href="https://www.thecheesecakefactory.com/">Cheesecake
Factory</a> avant de partir vers notre
prochain Airbnb à
<a href="https://fr.wikipedia.org/wiki/Bridgewater_(Massachusetts)">Bridgewater</a>.
C’est un peu perdu mais on ne s’attardera pas dans le coin, on cherchait juste
un endroit pas trop cher pour se poser sur le chemin de Cape Cod.</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=42.268671&n2=-70.587845&n3=10&a=42.509276,-70.902952,42.357529,-71.051502,41.974796,-70.973359&b=2&c=1&g1=-1&g2=0&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 9: Cape Cod et retour (500km, 5h45)</h2>
<p style="text-align: center">
<a href="https://www.google.fr/maps/dir/Bridgewater,+Massachusetts+02324/Provincetown,+Massachusetts/Ocean+View+Hill,+Provincetown,+Massachusetts/Wellfleet,+Massachusetts/White+Cedar+Swamp+Trail,+Wellfleet,+Massachusetts/Eastham,+Massachusetts/Chatham,+Massachusetts/New+Haven,+Connecticut/@41.8620516,-72.3750795,8.5z/data=!4m50!4m49!1m5!1m1!1s0x89e491936dc1862f:0x80848e0fdb046149!2m2!1d-70.9750541!2d41.9903519!1m5!1m1!1s0x89fca780cf83c821:0xd8d2863ae0f05eda!2m2!1d-70.1786425!2d42.0584412!1m5!1m1!1s0x89fca7a34b428c85:0x15372aaab84f5a90!2m2!1d-70.205027!2d42.0737136!1m5!1m1!1s0x89fb42dcc768c5df:0x17a139b6d6b512b0!2m2!1d-70.0309753!2d41.9305468!1m5!1m1!1s0x89fb6695fc2373e5:0xf837b48a7f77158e!2m2!1d-69.9731603!2d41.9134315!1m5!1m1!1s0x89fb68ec67201e37:0x4a489422124dadd!2m2!1d-69.9740361!2d41.8299634!1m5!1m1!1s0x89fb142168afbe53:0x714436ec7d485a53!2m2!1d-69.9597664!2d41.6820897!1m5!1m1!1s0x89e7d8443a8070e5:0xf6a354c659b264ed!2m2!1d-72.9278835!2d41.308274!3e0">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/canada_jour_9.png" alt="Itinéraire jour 9"/>
</a>
</p>
<p>Dernier jour de ce road trip, à <a href="https://fr.wikipedia.org/wiki/Cap_Cod">Cape
Cod</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02954.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02954.JPG" alt="Cape Cod"/>
</a>
</p>
<p>On décide d’aller jusqu’au bout de la péninsule, à
<a href="https://fr.wikipedia.org/wiki/Provincetown">Provincetown</a>. On découvre cette
ville qui a l’air d’être aux bostoniens la même chose que la Normandie aux
parisiens :) On découvre aussi des drapeaux arc-en-ciel partout, visiblement
la ville est une destination très prisée des gays. On fait un tour en
centre-ville, sur le port et on va voir le <a href="https://www.pilgrim-monument.org/">Pilgrim
Monument</a>, un peu en hauteur.</p>
<p>Le midi, on mange à <a href="http://www.thecanteenptown.com/">The Canteen</a>, qui fait
des <em>lobster rolls</em> et des sandwiches aux huîtres frites (c’est bien meilleur
que ce qu’on pourrait penser !).</p>
<p>Il y a un <a href="https://stellwagen.noaa.gov/">sanctuaire marin</a> près de Cape Cod,
et on peut donc faire des croisières pour observer les baleines, au départ de
Boston ou de Provincetown (le prix est similaire, mais le trajet avant
d’arriver sur les lieux est plus court depuis Provincetown). On voulait le
faire mais c’était un des derniers jours possibles de la saison, et il y avait
trop de vent pour que le bateau puisse sortir. Tant pis, pas de regret, ça
nous a permis de bien explorer Cape Cod, et on a fini par pouvoir le faire
pendant un autre voyage (voir les notes en bas de l’article).</p>
<p>L’après-midi, on va jusqu’au <a href="http://www.openstreetmap.org/node/358260342">point de
vue</a> à côté de Province Lands,
pour voir tout le bout de la péninsule.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02937.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02937.JPG" alt="Plage à Cape Cod"/>
</a>
</p>
<p>On repart ensuite vers le continent, en s’arrêtant d’abord voir le village de
<a href="https://en.wikipedia.org/wiki/Wellfleet,_Massachusetts">Wellfleet</a> (un ancien
village de pêcheurs) puis on va se balader sur le <a href="https://www.nps.gov/caco/planyourvisit/atlanticwhitecedar.htm">White Cedar Swamp
Trail</a>,
terrifiés par une pancarte au début du sentier annonçant “zone infestée de tiques”.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC02984.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC02984.JPG" alt="White Cedar Swamp Traim"/>
</a>
</p>
<p>On continue ensuite jusqu’à
<a href="https://www.nps.gov/caco/planyourvisit/coast-guard-beach-eastham.htm">Eastham</a>
pour aller voir la plage et la maison des gardes-côtes. On finit la journée à
<a href="https://fr.wikipedia.org/wiki/Chatham_(Massachusetts)">Chatham</a> où on voit
des phoques nager dans le port. On n’aura pas vu de baleines, mais on aura
quand même réussi à voir des phoques ! Visiblement, c’est assez facile d’en
voir à Cape Cod, et voici les <a href="https://www.capecod.com/wp-content/uploads/sealsInfographic_high.jpg">meilleurs
endroits</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/canada/DSC03001.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/canada/DSC03001.JPG" alt="Phoques"/>
</a>
</p>
<p>On repart direction New Haven, où on arrive dans la soirée.</p>
<p>La carte du trajet de la journée est
<a href="https://www.google.fr/maps/dir/Bridgewater,+Massachusetts+02324/Provincetown,+Massachusetts/Ocean+View+Hill,+Provincetown,+Massachusetts/Wellfleet,+Massachusetts/White+Cedar+Swamp+Trail,+Wellfleet,+Massachusetts/Eastham,+Massachusetts/Chatham,+Massachusetts/New+Haven,+Connecticut/@41.8620516,-72.3750795,8.5z/data=!4m50!4m49!1m5!1m1!1s0x89e491936dc1862f:0x80848e0fdb046149!2m2!1d-70.9750541!2d41.9903519!1m5!1m1!1s0x89fca780cf83c821:0xd8d2863ae0f05eda!2m2!1d-70.1786425!2d42.0584412!1m5!1m1!1s0x89fca7a34b428c85:0x15372aaab84f5a90!2m2!1d-70.205027!2d42.0737136!1m5!1m1!1s0x89fb42dcc768c5df:0x17a139b6d6b512b0!2m2!1d-70.0309753!2d41.9305468!1m5!1m1!1s0x89fb6695fc2373e5:0xf837b48a7f77158e!2m2!1d-69.9731603!2d41.9134315!1m5!1m1!1s0x89fb68ec67201e37:0x4a489422124dadd!2m2!1d-69.9740361!2d41.8299634!1m5!1m1!1s0x89fb142168afbe53:0x714436ec7d485a53!2m2!1d-69.9597664!2d41.6820897!1m5!1m1!1s0x89e7d8443a8070e5:0xf6a354c659b264ed!2m2!1d-72.9278835!2d41.308274!3e0">ici</a>
(chez Google car OpenStreetMap ne savait pas calculer le trajet :/).</p>
<h2>Quelques notes</h2>
<ul>
<li>Le stationnement est souvent assez facile. Si vous logez dans un Airbnb, il
y aura souvent la possibilité de se garer gratuitement dans la rue. Au
Canada, attention aux panneaux de stationnement qui ont des empilements
d’exceptions et de cas particuliers et souvent souvent très durs à lire !</li>
</ul>
<h2>Si vous avez un peu plus de temps</h2>
<h3>À Québec</h3>
<p>Il y a pleins de parcs nationaux à proximité qui ont tous l’air supers:
<a href="http://www.parcsregionaux.org/parcs-regionaux/parcs/parc-regional-des-sept-chutes/">Sept-Chutes</a>,
le <a href="https://www.sepaq.com/pq/sag/">Fjord-du-Saguenay</a> et la
<a href="https://www.pc.gc.ca/fr/pn-np/qc/mauricie">Mauricie</a>.</p>
<p>Si vous ne venez pas trop tard dans le mois d’octobre, vous pouvez descendre
la Jacques-Cartier en kayak (un bus vous amène en amont). Il paraît que c’est
super, surtout quand les arbres ont toutes leurs couleurs.</p>
<h3>À Boston</h3>
<ul>
<li>Quelques restaus sympas dans <a href="https://fr.wikipedia.org/wiki/Harvard_Square">Harvard
Square</a>: le <a href="http://www.veggiegalaxy.com/">Veggie
Galaxy</a> (restaurant végétarien, supers
salades, très hipster), le <a href="http://www.mainely-burgers.com/">Mainely Burger</a>
(pour des burgers un peu originaux), le <a href="http://theloniousmonkfish.com/">Thelonious
Monkfish</a> (<em>asian-fusion</em>) et le <a href="http://www.openstreetmap.org/node/2709425519">Brookline
Lunch</a> (pour un super brunch,
attention <em>cash only</em>).</li>
<li>Faire du shopping dans <a href="https://fr.wikipedia.org/wiki/Back_Bay">Back Bay</a>.</li>
<li>Aller visiter la <a href="http://www.bpl.org/">Boston Public Library</a> (gratuit, au
moins aussi belle que celle de New York).</li>
<li>Faire un tour dans <a href="https://fr.wikipedia.org/wiki/Beacon_Hill_(Boston)">Beacon
Hill</a> et ses maisons en
brique victoriennes.</li>
<li>Aller voir les <a href="http://www.bostonharborcruises.com/">baleines</a> au large de
Boston (ou en partant de Provincetown) ! Boston Harbor Cruises a des gros
catamarans et emmène toujours un naturaliste à bord pour vous donner plus
d’informations sur les baleines. Des notes sont disponibles <a href="http://www.bostonharborcruises.com/naturalists-notes/">en
ligne</a> après chaque
sortie, et si vous ne voyez pas de baleines pendant votre sortie (ça a l’air
assez rare quand même), vous pouvez revenir gratuitement. Le jour où on l’a
fait, il y avait des vagues d’un mètre et j’ai été malade tout le long du
trajet… mais c’était impressionnant de voir des énormes baleines d’aussi
près. Je m’attendais à ce qu’on soit assez loin des baleines et que ce ne
soit pas si bien que ça, mais pas du tout !</li>
</ul>
<h2>Quelques références</h2>
<ul>
<li>Le blog de <a href="https://www.maathiildee.com/">Mathilde</a>, une française installée
à Boston et qui écrit beaucoup sur ses <em>roadtrips</em>, une super source
d’inspiration !</li>
</ul>10 jours en Californie et au Nevada2017-11-19T11:53:00+01:002017-11-19T11:53:00+01:00Phykstag:localhost,2017-11-19:/Blog/output/2017/11/10-jours-en-californie-et-au-nevada.html<p>Je suis aux États-Unis en ce moment, et j’ai pu poser une semaine, pour aller
faire un tour. On n’était encore jamais allé dans le grand Canyon, donc
c’était l’occasion. En plus, en cette saison (mi-octobre), le temps est top et
change du froid de la …</p><p>Je suis aux États-Unis en ce moment, et j’ai pu poser une semaine, pour aller
faire un tour. On n’était encore jamais allé dans le grand Canyon, donc
c’était l’occasion. En plus, en cette saison (mi-octobre), le temps est top et
change du froid de la côte est !</p>
<p>Voici notre itinéraire (ambitieux, quelques jours de plus auraient été plus confortables).</p>
<h2>Jour 0 : New York -> San Francisco</h2>
<p>Départ de New York pour San Francisco le vendredi soir tard (22h), ça laisse
le temps d’arriver tranquillement à l’aéroport. Six heures de vol plus tard
(et trois heures de décalage horaire), nous voici à 1h du matin à San
Francisco. Direction le Airbnb et dodo !</p>
<h2>Jour 1 : San Francisco</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=37.796475&n2=-122.408273&n3=15&a=37.783871,-122.408433,37.78393,-122.406521,37.787829,-122.408327,37.802064,-122.419662,37.806927,-122.422933,37.809705,-122.410102,37.787829,-122.408327,37.79068,-122.405615,37.802376,-122.405841,37.797392,-122.406004,37.801073,-122.398218,37.790285,-122.39386,37.786841,-122.409648&b=2&c=0&g1=-1&g2=0&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/californie_jour_1.png" alt="Itinéraire jour 1"/>
</a>
</p>
<p>Premier jour de ce <em>roadtrip</em> à San Francisco. On profite du décalage horaire
dans le sens favorable (et de l’absence de rideaux) pour se lever tôt et
direction l’arrêt de <span class="caps">BART</span> le plus proche, descente à Powell Street.</p>
<p>Il y a <a href="http://www.openstreetmap.org/way/332627424">un grand centre
commercial</a> en face de la station
de <span class="caps">BART</span>, l’occasion de faire un peu de shopping (American Eagle, Hollister,
Abercrombie, Levis’s, Old Navy, etc), et de trouver un maillot de bain, si on
est parti sans :)</p>
<p>Puis nous avons longé la ligne de <a href="https://fr.wikipedia.org/wiki/Tramway_%C3%A0_traction_par_c%C3%A2ble"><em>cable
car</em></a> à
pied (sans pouvoir la prendre, elle était interrompue pour la journée) jusqu’à
Fisherman’s Wharf, en en profitant pour passer à <a href="https://fr.wikipedia.org/wiki/Union_Square_(San_Francisco)">Union
Square</a>, admirer
la vue au croisement de Powell et California St et aller faire un tour sur
<a href="https://fr.wikipedia.org/wiki/Lombard_Street_(San_Francisco)">Lombard
Street</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC04567.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC04567.JPG" alt="Lombard Street" />
</a>
</p>
<p>On arrive au <a href="https://www.nps.gov/safr/learn/historyculture/aquatic-park-pier.htm">Aquatic Park
Pier</a> où
de nombreux locaux nagent (dans l’eau gelée de la baie !) et où l’on peut
admirer les <a href="http://www.openstreetmap.org/way/25319880">bateaux historiques</a>
et la vue sur <a href="https://fr.wikipedia.org/wiki/%C3%8Ele_d%27Alcatraz">Alcatraz</a>.
Puis on remonte Jefferson Street en traversant <a href="https://fr.wikipedia.org/wiki/Fisherman%27s_Wharf_(San_Francisco)">Fisherman’s
Wharf</a> (et
en cherchant un endroit pour manger) jusqu’à <a href="https://fr.wikipedia.org/wiki/Jet%C3%A9e_39">Pier
39</a>, célèbre pour les lions de
mer qui y ont élu domicile.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC04580.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC04580.JPG" alt="Pier 39"/>
</a>
</p>
<p>Après manger, retour à Union Square en bus pour retrouver une amie avec qui
on devait faire un tour l’après-midi, puis on repart dans l’autre sens,
toujours à pied, à travers
<a href="https://fr.wikipedia.org/wiki/Chinatown_(San_Francisco)">Chinatown</a> (et
notamment la <a href="https://en.wikipedia.org/wiki/Dragon_Gate_(San_Francisco)">Dragon
Gate</a>).</p>
<p>On continue jusqu’à la <a href="http://sfrecpark.org/destination/telegraph-hill-pioneer-park/coit-tower/">Coit
tower</a>
(ça monte !) qui peut se visiter pour un prix raisonnable. Il y a des fresques
à l’intérieur, et une magnifique vue sur la baie en haut. On redescend dans
<a href="https://fr.wikipedia.org/wiki/North_Beach_(San_Francisco)">North Beach</a>, le
quartier italien, pour prendre un goûter, puis on finit la balade en remontant
<a href="https://fr.wikipedia.org/wiki/The_Embarcadero">Embarcadero</a> à pied, jusqu’au
<a href="https://fr.wikipedia.org/wiki/Financial_District_(San_Francisco)">Financial
District</a>,
le quartier des affaires de <span class="caps">SF</span>, désert un samedi soir.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC04604.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC04604.JPG" alt="Coit Tower"/>
</a>
</p>
<p>Pour manger le soir, on avait initialement prévu d’aller au <a href="https://www.thecheesecakefactory.com/">Cheesecake
Factory</a> sur Union Square, au dernier
étage du Macy’s, qui a une terrasse avec la vue sur la place, mais face aux
deux heures d’attente pour avoir une table, nous avons abandonné et nous
sommes réfugiés dans un <em>diner</em> à côté, <a href="http://lorisdiner.com/">Lori’s
Diner</a>. Ambiance garantie, et les <em>meatloafs</em> (sorte
de pains de viande) étaient top !</p>
<p>Conclusion de la journée : faire attention qu’à San Francisco, aucune rue
n’est plate, tout faire à pied est épuisant ! :)</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=37.796475&n2=-122.408273&n3=15&a=37.783871,-122.408433,37.78393,-122.406521,37.787829,-122.408327,37.802064,-122.419662,37.806927,-122.422933,37.809705,-122.410102,37.787829,-122.408327,37.79068,-122.405615,37.802376,-122.405841,37.797392,-122.406004,37.801073,-122.398218,37.790285,-122.39386,37.786841,-122.409648&b=2&c=0&g1=-1&g2=0&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 2 : San Francisco</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=37.754464&n2=-122.42825&n3=14&a=37.752256,-122.418449,37.751804,-122.412407,37.752256,-122.418449,37.762989,-122.420602,37.76146,-122.422579,37.764189,-122.426786,37.760054,-122.427349,37.7626,-122.435293,37.759767,-122.434754,37.75464,-122.44648,37.76938,-122.451928,37.770642,-122.443705&b=2&c=0&g1=-1&g2=0&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/californie_jour_2.png" alt="Itinéraire jour 2"/>
</a>
</p>
<p>Deuxième jour à San Francisco, pour faire un tour dans
<a href="https://fr.wikipedia.org/wiki/Mission_District_(San_Francisco)">Mission</a>,
<a href="https://fr.wikipedia.org/wiki/Le_Castro_(San_Francisco)">Castro</a>,
<a href="https://fr.wikipedia.org/wiki/Twin_Peaks_(San_Francisco)">Twin Peaks</a> et
<a href="https://fr.wikipedia.org/wiki/Haight-Ashbury">Haight-Ashbury</a>.</p>
<p>Direction l’arrêt de <span class="caps">BART</span> le plus proche, pour descendre à 24th Street
Mission, à proximité de <a href="https://en.wikipedia.org/wiki/Balmy_Alley">Balmy
Alley</a>, une des ruelles de Mission
District célèbre pour ses fresques (<em>murals</em>) engagées. On trouve pleins de <em>coffee
shops</em> dans le quartier, idéal pour prendre un petit déjeuner. Puis on a
remonté Mission St jusqu’à la 16th Street, en passant devant <a href="http://www.openstreetmap.org/way/173122150">des vieux
cinémas</a> et des magasins
<em>vintage</em>, pour aller voir la deuxième ruelle célèbre pour ses fresques :
<a href="https://en.wikipedia.org/wiki/Clarion_Alley">Clarion Alley</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC04648.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC04648.JPG" alt="Clarion Alley" />
</a>
</p>
<p>Depuis la bulle internet dans la Silicon Valley, de plus en plus de jeunes
urbains viennent habiter le quartier de Mission, faisant augmenter d’autant
les loyers. Les habitants précédents du quartier, principalement des classes
moyennes latino-américaines, sont chassés du quartier par les loyers élevés,
et les boîtes de nuit et bars remplacent les <em>taquerias</em>. Beaucoup de fresques
le dénoncent.</p>
<p>On continue ensuite de l’autre côté de Clarion Alley par un arrêt au
<a href="http://www.communitythriftsf.org/">Community Thrift</a>, un immense magasin
<em>vintage</em>, avant de se diriger vers le <a href="https://en.wikipedia.org/wiki/The_Women%27s_Building">Women’s
Building</a> et ses
magnifiques fresques, et le bâtiment historique de la <a href="https://fr.wikipedia.org/wiki/Mission_Saint-Fran%C3%A7ois-d%27Assise">Misión San Francisco de
Asís</a>.
C’était dimanche midi, et la basilique était ouverte (sinon, il y a moyen de
payer pour visiter l’église initiale et la basilique).</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC04653.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC04653.JPG" alt="Misión San Francisco de Asís" />
</a>
</p>
<p>On a ensuite traversé <a href="https://fr.wikipedia.org/wiki/Dolores_Park">Mission Dolores
Park</a> en profitant de la vue sur
Downtown, pour rejoindre le Castro, le quartier gay historique de San
Francisco. On est passé devant <a href="http://www.openstreetmap.org/way/225526801">Harvey Milk
plaza</a>, en hommage à <a href="https://fr.wikipedia.org/wiki/Harvey_Milk">Harvey
Milk</a> (un des premiers élus
ouvertement gay), et son immense drapeau arc-en-ciel qui flotte au-dessus de
la ville, un <a href="http://www.openstreetmap.org/way/99776277">vieux cinéma</a> et <a href="https://en.wikipedia.org/wiki/Castro_Camera">la
boutique de photos que tenait Harvey
Milk</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC04662.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC04662.JPG" alt="Castro" />
</a>
</p>
<p>On prend un hot-dog au passage sur Castro Street, puis on se lance à l’assaut
de Twin Peaks (et ça monte à nouveau !), pour profiter de la vue sur tout San
Francisco de là haut. En haut, on voulait redescendre sur Haight-Ashbury de
l’autre côté des collines, en <span class="caps">VTC</span> par pure flemme, mais le <span class="caps">VTC</span> n’a jamais
trouvé comment monter, donc redescente à pied… Il ne faut donc pas trop
compter sur un <span class="caps">VTC</span> pour monter ou descendre de Twin Peaks :)</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC04667.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC04667.JPG" alt="Twin Peaks" />
</a>
</p>
<p>Enfin, on a fait un petit tour dans Haight-Ashbury, en remontant Haight Street
jusqu’à Ashbury Street (et en s’arrêtant regarder les magasins de vêtements
<em>vintage</em> et de vinyles :)), avant de partir pour l’aéroport à temps pour notre
vol direction Las Vegas !</p>
<p>Arrivée à 20h30 à Las Vegas, 15 minutes à marcher dans l’aéroport pour
comprendre comment rejoindre le centre de location de voitures (tous les
loueurs sont ensemble, dans un endroit légèrement à l’écart des terminaux, et
il faut prendre un bus gratuit pour y aller). 21h30, on récupère notre
voiture, une Nissan Juke, puis direction le Trump (beurk) hotel pour la nuit !</p>
<p><em>Spoiler :</em> La chambre était plus grande que notre appartement à Paris, il y
avait douche et jacuzzi dans la chambre, mais il y avait trop de vent pour
aller sur la piscine (extérieure, au 7e étage). Et tout ça en plein désert…
Pas de casino dans l’hôtel par contre, on découvrira ça plus tard.</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=37.754464&n2=-122.42825&n3=14&a=37.752256,-122.418449,37.751804,-122.412407,37.752256,-122.418449,37.762989,-122.420602,37.76146,-122.422579,37.764189,-122.426786,37.760054,-122.427349,37.7626,-122.435293,37.759767,-122.434754,37.75464,-122.44648,37.76938,-122.451928,37.770642,-122.443705&b=2&c=0&g1=-1&g2=0&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 3 : Las Vegas -> Page (470km, 5h15)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=36.65777&n2=-113.293128&n3=8&a=36.129583,-115.172635,36.903471,-111.414671,36.937655,-111.483984,36.920165,-111.461442&b=0&c=0&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/californie_jour_3.png" alt="Itinéraire jour 3"/>
</a>
</p>
<p>Après un arrêt chez Walgreens pour prendre des bidons d’eau et un pique-nique,
départ pour <a href="http://www.openstreetmap.org/way/33019115">Page</a>, une ville au
nord du Grand Canyon. Là-bas, on avait une visite (guidée) de <a href="https://fr.wikipedia.org/wiki/Antelope_Canyon#Lower_Antelope_Canyon">Lower Antelope
Canyon</a>
en fin d’après-midi.</p>
<p><em>Info pratique :</em> En théorie Walgreens est une chaine de pharmacies. En
pratique, ils vendent non seulement ce qu’on peut trouver dans une pharmacie,
mais ont toujours des produits alimentaires à côté. C’est un mélange entre une
supérette et une pharmacie française.</p>
<p>Peu après le départ, grosse frayeur sur l’Interstate 15 quand les voitures
devant nous s’arrêtent brutalement, et que celle derrière nous continue sa
route et nous rentre dedans.</p>
<p><em>Info pratique :</em> Il y a essentiellement une route principale, qui est une
autoroute, l’Interstate 15, pour se déplacer dans Las Vegas et en sortir.
Votre <span class="caps">GPS</span> vous conseillera sûrement toujours de la prendre. Il y a le Las
Vegas Boulevard (le Strip) aussi, mais il est souvent bouché, et beaucoup
moins rapide. Problème : le trafic est très dense sur l’I15, et peut s’arrêter
brutalement, à chaque entrée ou sortie. Faites très attention si vous roulez
sur les voies les plus à droite, gardez vos distances et sachez que les
américains qui roulent derrière vous ne respecteront sûrement pas les
distances de sécurité…</p>
<p><em>Info pratique en cas d’accident :</em> Si vous avez un accident (même sans
gravité) sur une autoroute aux États-Unis, il faut appeler le 911, le numéro
d’urgence, et la police viendra. C’est le policier qui prendra vos
déclarations, rédigera un constat et vous donnera un reçu pour obtenir le
constat complet. Si en plus vous avez une voiture de location, il faut appeler
votre loueur avec votre numéro de réservation et le numéro donné par le
policier pour ouvrir un “dossier d’accident”. Si vous n’avez pas pris de
garantie supplémentaire contre les dommages (si vous avec une carte Premier),
j’imagine qu’il faut aussi appeler votre assurance à ce moment-là.</p>
<p>Dans notre cas, ouf, on a juste été secoué, mais la voiture ne peut pas
continuer. On avait loué chez Alamo qui fait <a href="http://www.alamo-affiliate.de/isic/isic_eng.htm">des packs très
avantageux</a> pour les
détenteurs d’une carte <span class="caps">ISIC</span> (étudiants), incluant la protection étendue en cas
de dommages à la voiture. Retour au centre de location, changement de voiture
(on a désormais une Kia Soul, vraiment mieux que la Nissan Juke précédente :))
sans soucis (les vendeurs en voient trois comme ça par jour à Las Vegas…) et on
repart en direction de Page en espérant être à l’heure malgré les deux heures
perdues avec cette histoire !</p>
<p>En chemin, on passe par des coins chouettes, mais on n’a pas trop le temps de
s’arrêter. On passe du Nevada à l’Arizona sans s’en rendre compte, mais nos
téléphones se décalent d’une heure sans que l’on ne comprenne jamais pourquoi.</p>
<p><em>Info pratique :</em> Visiblement, il y a des subtilités avec les fuseaux horaires
dans la région. Le Nevada et la Californie sont sur le même fuseau horaire.
Pour l’Arizona, on n’a pas compris et on a fini par appeler Lower Antelope
Canyon pour être sûr d’être à la même heure :p Mi-octobre, on n’a jamais
changé d’heure. Il y a quelques explications
<a href="http://www.sunsetbld.com/preparer-voyage-usa/fuseaux-horaires/">ici</a>, mais
beaucoup trop d’exceptions d’exceptions. :)</p>
<p>Il y a deux canyons que l’on peut visiter à côté de Page : Lower Antelope
Canyon et Upper Antelope Canyon. On ne pouvait pas faire les deux, et internet
avait l’air de dire que Lower Antelope Canyon était très bien et moins cher.
Je ne sais pas comment est Upper Antelope Canyon, mais Lower Antelope Canyon
était vraiment top !</p>
<p>Pour Lower Antelope Canyon, il y a deux compagnies qui proposent des visites
(à pied, autour de 30$) : <a href="http://lowerantelope.com/">Ken’s</a> et <a href="https://antelopelowercanyon.com/">Dixie
Ellis’</a>. Il y a aussi des tours spéciaux
pour les photographes, qui sont des tours avec moins de monde et plus de temps
pour s’arrêter prendre des photos. On avait choisi un tour normal avec Dixie
Ellis’ (sur les conseils d’un obscur commentaire sur internet, mais les deux
ont l’air très similaires :)). Les deux compagnies sont gérées par des frères
et sœurs qui se sont partagés la concession de leur père. Il vaut mieux
réserver en avance si vous ne passez pas beaucoup de temps dans le coin et
n’êtes pas très flexibles.</p>
<p>Voyant qu’on aurait du retard à cause de l’accident, on avait appelé pour
décaler la visite d’une heure, sans trop y croire, et ça n’a posé aucun
problème !</p>
<p>Une fois arrivé au pied de l’horrible <a href="http://www.openstreetmap.org/way/217473025#map=15/36.9052/-111.3887">station
électrique</a>,
on est pris en charge par un guide Navajo (Antelope Canyon est situé en terre
Navajo), et on attend presque une heure avant de pouvoir rentrer dans le
canyon. On marchera ensuite pendant une grosse heure dans le canyon, pour
ressortir à côté du parking. Toute la visite de Lower Antelope Canyon se fait
à pied contrairement à Upper Antelope Canyon pour lequel il y a un départ en
4x4. Le guide était super sympa et nous a fait des tours de magie pendant
qu’on attendait pour pouvoir rentrer dans le canyon (il allait auditionner
pour America’s Got Talent ! :)).</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC04695.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC04695.JPG" alt="Lower Antelope Canyon" />
</a>
</p>
<p>On est parti avec la dernière visite de la journée, ce qui avait l’énorme
avantage que la visite était beaucoup plus relax, nous laissant pas mal de
temps pour prendre les photos (sans trop de monde dessus :)). Le soleil était
très bas, et le canyon était assez sombre, mais on a pu prendre plein de
photos quand même. Pour avoir la meilleure lumière et les rayons de soleil,
l’idéal est de venir en fin de matinée visiblement.</p>
<p>Une fois sortis, direction <a href="https://fr.wikipedia.org/wiki/Barrage_de_Glen_Canyon">Glen Canyon
Dam</a>, un barrage à 10
minutes en voiture, construit sur le Colorado et qui a entrainé la formation
du Lac Powel. Puis direction notre motel pour la nuit, le <a href="http://www.thepageboymotel.com/">Page Motel
Boy</a>, un motel un peu cher (mais il n’y avait
guère d’options meilleur marché à côté) et très bien. Repas chez
<a href="http://slackersqualitygrub.com/">Slackers</a>, sur les conseils de Google, qui
fait de super (énormes) burgers à des prix très raisonnables.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC04830.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC04830.JPG" alt="Glen Canyon" />
</a>
</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=36.65777&n2=-113.293128&n3=8&a=36.129583,-115.172635,36.903471,-111.414671,36.937655,-111.483984,36.920165,-111.461442&b=0&c=0&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 4 : Grand Canyon (400km, 4h30)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=35.570215&n2=-112.843323&n3=8&a=36.920165,-111.461442,36.742314,-111.603983,36.817317,-111.631793,35.940496,-111.671048,36.057066,-112.140867,35.245947,-111.68663,35.214582,-111.597656&b=0&c=0&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/californie_jour_4.png" alt="Itinéraire jour 4"/>
</a>
</p>
<p>Pour ce quatrième jour, direction le sud, pour aller voir le <a href="https://www.nps.gov/grca/index.htm">Grand Canyon
National Park</a> (South Rim).</p>
<p><em>Note :</em> Il y a plusieurs endroits pour voir le Grand Canyon. Une partie est
gérée par les parcs nationaux des États-Unis : c’est le <a href="http://www.openstreetmap.org/way/124669358#map=11/35.9196/-113.6790">South
Rim</a> et
le <a href="http://www.openstreetmap.org/node/1183478315#map=14/36.2006/-112.0512">North
Rim</a>
(de chaque côté du canyon), qui font partie du Grand Canyon National Park.
North Rim est un peu isolé et excentré, donc nous sommes allés sur la partie
South Rim, qui a l’air d’être la plus touristique. Il y a également <a href="https://www.grandcanyonwest.com/">Grand
Canyon West</a>, dans la réserve indienne
Hualapai, qui possède notamment la Skywalk (le pont en verre au-dessus du
canyon). Les attractions sont assez chères et très touristiques et nous n’y
sommes pas allés.</p>
<p>Après l’arrêt achat de pique-nique quotidien, direction <a href="https://fr.wikipedia.org/wiki/Horseshoe_Bend_(Arizona)">Horseshoe
Bend</a>, un méandre du
fleuve Colorado. Bien compter une grosse heure là-bas, entre les 15 minutes de
marche pour atteindre le point de vue et le temps de faire un tour pour
prendre quelques photos et profiter du point de vue.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC04857.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC04857.JPG" alt="Horseshoe Bend" />
</a>
</p>
<p>On continue ensuite en direction de Bitter Springs, puis on fait un petit
détour pour aller voir <a href="https://en.wikipedia.org/wiki/Navajo_Bridge">Navajo
Bridge</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC04950.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC04950.JPG" alt="Navajo Bridge" />
</a>
</p>
<p>On reprend la route en direction du Grand Canyon, en rentrant dans le parc par
la route 64. Il y a plusieurs arrêts avec des points de vue sur la route,
indiqués par des panneaux “Scenic view”.</p>
<p>Juste avant de rentrer dans le Grand Canyon National Park, il y a un arrêt
possible sur la droite, indiqué par un panneau <a href="https://www.google.fr/maps/place/Little+Colorado+River+Navajo+Tribal+Park/@35.9215747,-111.5688379,13z/data=!4m5!3m4!1s0x8733b15a159d0905:0xba2b81cce97d964e!8m2!3d35.9178675!4d-111.5643167">Little Colorado
River</a>.
C’est un parc tribal, c’est-à-dire géré par les Navajos, qui est la seule
partie du Grand Canyon qu’il leur reste. L’entrée est payante à prix libre
(aucun montant n’est suggéré), mais la vue est formidable, même si ça ne paye
pas de mine du bord de la route ! On se retrouve en haut d’un canyon
surplombant la Little Colorado River, et c’est très impressionnant. Il y a
aussi des tables de pique-nique et des toilettes. Il y a un autre parking un
peu plus loin, marqué “Scenic view” et gratuit, je ne sais pas ce qu’il vaut
et s’il est équivalent ou pas.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC04992.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC04992.JPG" alt="Little Colorado River" />
</a>
</p>
<p>En continuant sur la route 64, on entre dans le Grand Canyon National Park, où
l’on paye l’entrée de 30$ pour une voiture, valable une semaine.</p>
<p><em>Info pratique :</em> Si comme nous vous prévoyez de visiter plusieurs parcs
nationaux dans l’année (par exemple Yosemite et la Vallée de la Mort), il
existe un pass annuel valide pour le détenteur et les personnes dans sa
voiture pendant un an pour 80$. Juste pour Yosemite, la Vallée de la Mort et
le Grand Canyon, ça fait 5$ d’économies. Vous pouvez toujours convertir votre
entrée en un pass au parc national suivant, mais il faut alors bien garder le
reçu de vos entrées pour les présenter.</p>
<p>Dans le Grand Canyon, il y a essentiellement une seule route et le <em>ranger</em>
vous donnera <a href="https://www.nps.gov/grca/learn/news/upload/sr-pocket-map.pdf">une carte à
l’entrée</a>, avec
tous les points de vue listés le long de la route. Attention, l’échelle change
au milieu de la carte, et on se fait facilement avoir ! Il y a un service de
navettes gratuites dans le parc national, et certains endroits ne sont
accessibles qu’en navette.</p>
<p>On s’est arrêté à <a href="https://www.google.fr/maps/place/Desert+View+Watchtower/@36.0153611,-111.8564079,13.25z/data=!4m13!1m7!3m6!1s0x873310bc3380065f:0x98eab41e380dae2c!2sGrand+Canyon+Park+Headquarters,+Grand+Canyon+Village,+AZ+86023,+%C3%89tats-Unis!3b1!8m2!3d36.054858!4d-112.1222962!3m4!1s0x8733a9ba161d0431:0x9af0f5028f24e21e!8m2!3d36.0440676!4d-111.8261433">Desert
View</a>
où on a le premier panorama sur le Grand Canyon du haut de la tour de garde,
puis à <a href="https://www.google.fr/maps/place/Navajo+Point/@36.0153611,-111.8564079,13.25z/data=!4m13!1m7!3m6!1s0x873310bc3380065f:0x98eab41e380dae2c!2sGrand+Canyon+Park+Headquarters,+Grand+Canyon+Village,+AZ+86023,+%C3%89tats-Unis!3b1!8m2!3d36.054858!4d-112.1222962!3m4!1s0x0:0xe3695585d2769758!8m2!3d36.0385068!4d-111.8373871">Navajo
Point</a>,
<a href="https://www.google.fr/maps/place/Grandview+Point/@35.9789111,-111.9976745,13.25z/data=!4m5!3m4!1s0x0:0x8ba03dfd7c969c10!8m2!3d35.9984762!4d-111.9877517">Grandview
Point</a>,
puis dans <a href="https://www.google.fr/maps/place/Grand+Canyon+Village,+Arizona+86023,+%C3%89tats-Unis/@36.0459052,-112.1871056,13z/data=!3m1!4b1!4m5!3m4!1s0x8733174f95ffe325:0xb8ccc2749a229ea1!8m2!3d36.0545116!4d-112.1400261">Grand Canyon
Village</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05021.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05021.JPG" alt="Grand Canyon" />
</a>
</p>
<p>On voulait faire une petite balade (une heure ou deux), pour s’éloigner un peu
de la route et descendre un petit peu dans le canyon (sans aller jusqu’au
fleuve Colorado, il faut compter au moins une journée pour ça !) et on est
parti sur le <a href="https://www.google.fr/maps/place/Bright+Angel+Trailhead/@36.0577691,-112.1492012,14.25z/data=!4m5!3m4!1s0x87331735570246ef:0x864e99540608b624!8m2!3d36.0571918!4d-112.1436042">Bright Angel
Trail</a>
(qui descend très vite, ça nous manquait les côtes depuis <span class="caps">SF</span> !).</p>
<p>On a essayé de voir le coucher de soleil sur le Grand Canyon, et on est allé à
<a href="https://www.google.fr/maps/place/Grandview+Point/@35.9905663,-111.9840619,14.75z/data=!4m5!3m4!1s0x8733046f5f02b3a3:0x8ba03dfd7c969c10!8m2!3d35.9984762!4d-111.9877517">Grandview
Point</a>
(qu’on pensait pas trop mal orienté) pour le voir, mais ce n’était pas aussi
impressionnant que prévu. Le canyon prenait quelques couleurs, mais le soleil
se couchait plutôt derrière nous. Le lever de soleil sur le Grand Canyon doit
être beaucoup mieux !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05141.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05141.JPG" alt="Grand Canyon" />
</a>
</p>
<p>On reprend la route jusqu’à Flagstaff, pour dormir. Flagstaff est située sur
l’ancienne <a href="https://fr.wikipedia.org/wiki/U.S._Route_66"><span class="caps">U.S.</span> Route 66</a> et
donc on trouve plein de motels plutôt confortables et très bon marché. Par
contre, il y a toujours des énormes trains longs de plusieurs kilomètres qui
passent, à longueur de journée (et la nuit !) en faisant beaucoup de bruit.</p>
<p>On l’a découvert trop tard, mais Flagstaff est aussi célèbre pour abriter le
<a href="https://lowell.edu/">Lowell Observatory</a>, l’observatoire qui a découvert
Pluton, en 1930. Du coup, Flagstaff est une ville “ciel noire”, qui fait
attention à réduire la pollution lumineuse, et le coin est un super endroit
pour observer les étoiles (en plus, il fait nuit à 18h30 en octobre) !
Le plateau de l’observatoire a l’air d’être un bon spot pour observer les
étoiles, et l’observatoire en lui-même propose des visites avec des
observations du ciel. Il y a aussi <a href="https://fr.wikipedia.org/wiki/Flagstaff_(Arizona)#Aux_alentours">quelques
trucs</a> à voir
dans les alentours immédiats de Flagstaff.</p>
<p>Le soir, on a dormi au <a href="https://www.booking.com/hotel/us/luxury-inn.fr.html">Mountain View
Inn</a> qui était très bien.
On entendait les trains siffler la nuit, mais vu comme ils sifflent forts, je
pense que c’est plus ou moins pareil dans tous les motels :) On a mangé à
l’<a href="https://www.outback.com/">Outback Steakhouse</a> (toujours sur les conseils de
Google), qui est une chaîne de restaurants de grillades, plutôt pas mal.</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=35.570215&n2=-112.843323&n3=8&a=36.920165,-111.461442,36.742314,-111.603983,36.817317,-111.631793,35.940496,-111.671048,36.057066,-112.140867,35.245947,-111.68663,35.214582,-111.597656&b=0&c=0&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 5 : Retour à Las Vegas (415km, 4h)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=35.229916&n2=-113.623352&n3=8&a=35.214582,-111.597656,36.016066,-114.739469,36.082062,-115.172786,36.147357,-115.155475&b=0&c=0&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/californie_jour_5.png" alt="Itinéraire jour 5"/>
</a>
</p>
<p>Pour ce cinquième jour, retour à Las Vegas en passant par le Hoover Dam, puis
balade sur le Strip.</p>
<p>Départ de Flagstaff le matin, direction <a href="https://fr.wikipedia.org/wiki/Barrage_Hoover">Hoover
Dam</a>, un grand barrage sur le
Colorado datant des années 1930. On sort de la 93 direction Hoover Dam et on
passe le contrôle policier (depuis 2001 la 93 ne passe plus sur le barrage).</p>
<p><em>Info pratique :</em> En bas, à proximité du barrage, il y a un parking payant,
mais en traversant le pont et en continuant un peu, il y a pleins de places de
parking gratuites, pour peu que l’on accepte de marcher un peu.</p>
<p>Après être passé sur le barrage, il ne faut pas rater le <a href="http://www.openstreetmap.org/way/82451320">Mike O’Callaghan -
Pat Tillman Memorial Bridge</a> qui
permet de passer le long du <a href="https://fr.wikipedia.org/wiki/Mike_O%27Callaghan-Pat_Tillman_Memorial_Bridge">Memorial
Bridge</a>
(le nouveau pont pour détourner le trafic du barrage Hoover) et de profiter
d’une super vue sur le barrage.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05187.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05187.JPG" alt="Hoover Dam" />
</a>
</p>
<p>En repartant, il y a aussi un <a href="http://www.openstreetmap.org/node/1183480121">point de
vue</a> sur le <a href="https://fr.wikipedia.org/wiki/Lac_Mead">lac
Mead</a>, le lac artificiel créé en amont
du barrage Hoover.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05189.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05189.JPG" alt="Lac Mead" />
</a>
</p>
<p>On repart ensuite pour Las Vegas, direction le <a href="http://www.stratospherehotel.com/">Stratosphere
Hotel</a>, notre hôtel pour la nuit. En
arrivant à Las Vegas, encore traumatisés par notre accident quelques jours
plus tôt, hors de question de reprendre la I15 et on décide de remonter le
Las Vegas Boulevard, ce qui nous permet de passer devant le panneau <a href="http://www.openstreetmap.org/way/135295757">Welcome
to Fabulous Las Vegas</a> et les
célèbres hôtels-casinos pour avoir un premier aperçu.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05195.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05195.JPG" alt="Welcome to Fabulous Las Vegas" />
</a>
</p>
<p>Le Stratosphere Hotel est <a href="http://www.openstreetmap.org/way/135456188">assez excentré sur le
Strip</a>, mais a l’énorme avantage
de permettre l’accès à la Stratosphere Tower (voir plus bas) pour 5$ (au lieu
de 20$). Les chambres étaient correctes, mais à la réception, c’est vraiment
l’usine. Il y a un casino dans l’hôtel et une piscine extérieure bien sympa
(mais qui ferme tôt, ensuite il faut passer au bar avec piscine, et c’est
moins bien).</p>
<p>Le plus simple pour ressortir sur le Strip et aller voir les grands hôtels et
casinos est probablement de prendre le
<a href="http://www.rtcsnv.com/touristms/routes.html">bus</a>, qui fonctionne 24h/24 et
fait de nombreux arrêts. Attention, les billets standards durent 2h et sont
assez chers, il vaut sûrement mieux opter pour un <a href="http://www.rtcsnv.com/touristms/fare.html">pass
24h</a>.</p>
<p>Les principaux casinos à voir sont :
* Le <a href="https://fr.wikipedia.org/wiki/Mandalay_Bay_Resort_and_Casino">Mandalay
Bay</a> (qu’on a
zappé, vu les événements),
* Le <a href="https://fr.wikipedia.org/wiki/Luxor_Las_Vegas">Luxor</a>, sur le thème de
l’Égypte ancienne, avec son sphinx et sa pyramide,
* L’<a href="https://fr.wikipedia.org/wiki/Excalibur_Hotel_and_Casino">Excalibur</a> et
ses tours de château fort,
* Le <a href="https://fr.wikipedia.org/wiki/New_York-New_York_Hotel_%26_Casino">New York New
York</a> et
son imitation de la Skyline newyorkaise,
* Le <a href="https://fr.wikipedia.org/wiki/Bellagio_Las_Vegas">Bellagio</a> et ses
fontaines, qui s’animent
<a href="http://www.office-tourisme-usa.com/etat/nevada/les-fontaines-du-bellagio">régulièrement</a>,
* Le <a href="https://fr.wikipedia.org/wiki/Paris_Las_Vegas">Paris</a> et sa copie de la
<a href="http://www.openstreetmap.org/way/27831699">tour Eiffel</a>,
* Le <a href="https://fr.wikipedia.org/wiki/Flamingo_Las_Vegas">Flamingo</a> et ses
<a href="http://www.openstreetmap.org/relation/6036585">flamands roses</a>,
* Le <a href="https://fr.wikipedia.org/wiki/Caesars_Palace">Caesars Palace</a> sur le
thème romain,
* Le <a href="https://fr.wikipedia.org/wiki/The_Mirage">Mirage</a> et son
<a href="http://www.openstreetmap.org/way/111339157">volcan</a> qui rentre en éruption,
* Le <a href="https://fr.wikipedia.org/wiki/The_Palazzo">Palazzo</a> et le
<a href="https://fr.wikipedia.org/wiki/The_Venetian_(Las_Vegas)">Venetian</a> avec
leurs répliques de bâtiments célèbres de Venise,</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05233.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05233.JPG" alt="Las Vegas" />
</a>
</p>
<p>Pour se déplacer sur le Strip, on peut tout faire à pied (compter une bonne
heure pour remonter du Mandalay Bay au Venetian). Il y a un <a href="https://www.mandalaybay.com/en/amenities/transportation.html#/MANDALAY%20BAY%20TRAM">tramway
automatique
gratuit</a>
entre le Mandalay Bay, le Luxor et l’Excalibur (qui ne dessert pas tous les
arrêts selon le sens dans lequel il circule). Il y a <a href="https://gamboool.com/las-vegas-tram-system-three-free-monorails-to-help-you-get-up-and-down-the-strip">trois tels trams
gratuits</a>.
Il y a aussi un <a href="https://www.lvmonorail.com/">monorail</a> assez cher, ou les bus
de la ville.</p>
<p>Le <a href="http://www.hardrock.com/cafes/las-vegas/">Hard Rock Café</a> de Las Vegas
était pas mal, et étonnement peu fréquenté. La liste des spectacles gratuits
dans les hôtels est
<a href="http://www.office-tourisme-usa.com/etat/nevada/les-fontaines-du-bellagio">ici</a>.</p>
<p>Avant d’aller se coucher, on est monté en haut de la <a href="https://www.vegas.com/attractions/on-the-strip/stratosphere-tower/">Stratosphere
Tower</a>.
C’est très impressionnant et la vue est top d’en haut. Et si vous êtes
téméraires, il y a même des
<a href="http://www.stratospherehotel.com/ThrillRides">attractions</a> sur le toit, à
270m de haut. On peut <a href="http://www.skyjumplv.com/">faire un saut de 260m dans le
vide</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05303.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05303.JPG" alt="Stratosphere Tower" />
</a>
</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=35.229916&n2=-113.623352&n3=8&a=35.214582,-111.597656,36.016066,-114.739469,36.082062,-115.172786,36.147357,-115.155475&b=0&c=0&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 6 : La vallée de la mort (560km, 6h)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=36.339466&n2=-116.858826&n3=8&a=36.147357,-115.155475,36.255213,-116.020142,35.956053,-116.304438,35.918873,-116.683539,36.230305,-116.767438,36.285961,-116.826131,36.367728,-116.803384,36.425461,-116.875441,36.606294,-117.115175,36.566051,-117.133982,37.648995,-118.972564&b=0&c=0&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/californie_jour_6.png" alt="Itinéraire jour 6"/>
</a>
</p>
<p>Sixième jour, on traverse la <a href="https://www.nps.gov/deva/index.htm">Vallée de la
mort</a>.</p>
<p>Départ de Las Vegas, direction
<a href="http://www.openstreetmap.org/way/33196497#map=12/35.9752/-116.2292">Shoshone</a>.
On fait un arrêt à <a href="http://www.openstreetmap.org/relation/170101">Pahrump</a> en
cours de route pour récupérer des bidons d’eau (voir les <a href="https://www.nps.gov/deva/planyourvisit/safety.htm">conseils de
sécurité</a>) et un
pique-nique, puis on arrive à Shoshone, la dernière pompe à essence avant
plusieurs centaines de milles. Par précaution, on complète le plein, malgré le
tarif prohibitif (plus de 4$ par gallon, contre autour de 2.8$ par gallon
normalement !).</p>
<p><em>Info pratique :</em> On pensait Shoshone beaucoup plus loin de Pahrump que ce
qu’il n’est en pratique. Rétrospectivement, on aurait dû reprendre de
l’essence à Pahrump, où les prix étaient beaucoup plus abordables et ne rien
prendre à Shoshone.</p>
<p>On rentre ensuite dans le parc national par le sud, par la 127, ce qui permet
de voir dans l’ordre :</p>
<ul>
<li>
<p><a href="https://en.wikipedia.org/wiki/Ashford_Mill,_California">Ashford Mills</a>, une
ancienne petite colonie minière, aujourd’hui en ruines.
<br>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05321.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05321.JPG" alt="Ashford Mills" />
</a>
</p></p>
</li>
<li>
<p><a href="https://fr.wikipedia.org/wiki/Badwater">Badwater Basin</a>, le point le plus
bas en Amérique du Nord avec une altitude de 85.5m sous le niveau de la mer.
Il y a une grande étendue de sel et de petits bassins d’eau non potable.
<br>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05352.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05352.JPG" alt="Badwater Basin" />
</a>
</p></p>
</li>
<li>
<p><a href="https://fr.wikipedia.org/wiki/Devil%27s_Golf_Course">Devil’s Golf Course</a>,
un plateau couvert d’étranges formations en sel. L’accès se fait par une
route en gravier de 2km, mais pas besoin d’un 4x4 pour y accéder, notre
petite Kia Soul a pu passer sans problème.
<br>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05393.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05393.JPG" alt="Devil's Golf Course" />
</a>
</p></p>
</li>
<li>
<p><a href="https://fr.wikipedia.org/wiki/Parc_national_de_la_vall%C3%A9e_de_la_Mort#Artist.27s_Palette">Artist’s
Palette</a>,
avec ses roches colorées et un point de vue sur la vallée. Il y a une route
à sens unique (goudronnée) de quelques kilomètres pour y accéder.
<br>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05420.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05420.JPG" alt="Artist's Palette" />
</a>
</p>
</p>
</li>
</ul>
<p><strong>Attention :</strong> En rentrant par le sud, on ne croise aucune caisse en entrant
dans le parc, contrairement au Grand Canyon. Je ne sais pas s’il y en a sur
les autres entrées. Il faut savoir qu’à partir de maintenant et jusqu’à être
bien sorti de la vallée de la Mort, votre téléphone n’aura pas de réseau
pendant 90% du temps. Ne comptez donc pas sur lui pour vous servir de <span class="caps">GPS</span>. Le
centre d’accueil des visiteurs, où vous payerez votre entrée et pourrez
prendre une carte, est à <a href="http://www.openstreetmap.org/way/203775852">Furnace
Creek</a>, à une petite heure de
route. Pensez donc à bien repérer vos arrêts (pas la route, c’est globalement
tout droit :)) en avance !</p>
<p>Finalement, on arrive à <a href="https://fr.wikipedia.org/wiki/Furnace_Creek">Furnace
Creek</a> la petite “ville” de la
vallée de la Mort. Il y a le centre d’accueil des visiteurs, où on paye son
entrée au parc (25$ pour une voiture, valable une semaine ou un pass, voir le
Grand Canyon) et on peut récupérer <a href="https://www.nps.gov/deva/planyourvisit/maps.htm">une
carte</a>, des points d’eau, et
une station essence au cas où. On a du bol, il ne fait pas trop chaud. Il ne
fait que 35°C et on pourra rouler toute la journée avec la climatisation sans problèmes.</p>
<p>On repart l’après-midi par l’ouest du parc, en s’arrêtant en chemin à
* <a href="https://fr.wikipedia.org/wiki/Parc_national_de_la_vall%C3%A9e_de_la_Mort#Mesquite_Sand_Dunes">Mesquite Flat Sand
Dunes</a>,
de grandes dunes de sable. C’est là qu’ont été tournées certaines scènes de
Star Wars (et d’autres films), car les dunes sont assez faciles d’accès.
<br>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05465.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05465.JPG" alt="Mesquite Flat Sand Dunes" />
</a>
</p></p>
<ul>
<li><a href="https://fr.wikipedia.org/wiki/Parc_national_de_la_vall%C3%A9e_de_la_Mort#Mosaic_Canyon">Mosaic
Canyon</a>,
un canyon très sympa dans lequel on peut <a href="https://www.nps.gov/deva/planyourvisit/hiking.htm#Mosaic">se
balader</a> (pas
obligé de faire toute la balade, le premier mille au fond du canyon est le
plus sympa visiblement, compter une heure). On y accède par une route en
gravier, très similaire à celle qui mène à Devil’s Golf Course. On avait
hésité avec <a href="https://www.nps.gov/deva/planyourvisit/golden-canyon.htm">Golden
Canyon</a> aussi,
mais on a raté le parking le long de la route…
<br>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05473.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05473.JPG" alt="Mosaic Canyon" />
</a>
</p>
</li>
</ul>
<p>On continue vers l’ouest en montant dans les montagnes et en passant le col de
<a href="http://www.openstreetmap.org/node/88385890">Towne Passe</a> avant de redescendre
sur Panamint Spring et la sortie de la vallée. On s’arrête prendre quelques
photos là où la route 190 traverse le <a href="http://www.openstreetmap.org/node/358787284">lac
Hill</a> (asseché), et aux points de
vue le long de la route.</p>
<p>On se dirige ensuite vers <a href="https://fr.wikipedia.org/wiki/Mammoth_Lakes">Mammoth
Lakes</a>, une station de ski dans
les montagnes, à une grosse heure de route où on passe la nuit. On s’arrête au
<a href="https://www.dennys.com/">Denny’s</a> (une chaîne de restaurants américains de
type <em>diner</em>, pas terrible mais bien cliché :)) de
<a href="http://www.openstreetmap.org/way/33114410">Bishop</a>.</p>
<p>On passe finalement la nuit au <a href="https://www.motel6.com/en/motels.ca.mammoth-lakes.276.html">Motel
6</a> de Mammoth
Lakes. Le motel est top, tout neuf et à un tarif raisonnable. On flippe juste
un peu en voyant toutes les affiches rappelant les règles de sécurité relatives
aux ours :).</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=36.339466&n2=-116.858826&n3=8&a=36.147357,-115.155475,36.255213,-116.020142,35.956053,-116.304438,35.918873,-116.683539,36.230305,-116.767438,36.285961,-116.826131,36.367728,-116.803384,36.425461,-116.875441,36.606294,-117.115175,36.566051,-117.133982,37.648995,-118.972564&b=0&c=0&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 7 : Yosemite National Park (330km, 5h)</h2>
<p style="text-align: center">
<a href="https://www.google.fr/maps/dir/Motel+6+Mammoth+Lakes/Mono+lake+-+South+Tufa+Area/Tioga+Pass+Rd,+California/Tuolumne+Grove+Trailhead/Bridalveil+Fall+Viewing+Point/Tunnel+View/Vernal+Falls+Bridge,Yosemite+Village/Mirror+Lake/Lower+Yosemite+Fall+Trail/Americas+Best+Value+Inn+Merced/@37.6236534,-120.2692213,9z/data=!3m1!4b1!4m62!4m61!1m5!1m1!1s0x80960dc9646c4d91:0x3ce9d42ff47ca4ca!2m2!1d-118.972519!2d37.649113!1m5!1m1!1s0x8096388a4a162e19:0x4f111f0afdedb852!2m2!1d-119.0269924!2d37.9386734!1m5!1m1!1s0x8096f7835559cfc3:0xf13f8b5f454d862f!2m2!1d-119.4454537!2d37.8472262!1m5!1m1!1s0x8096c2b0ba302b5d:0x334dfa09f120a1ec!2m2!1d-119.805421!2d37.7581939!1m5!1m1!1s0x8096ec3a87498f41:0x616838fc29f68fa8!2m2!1d-119.647734!2d37.7169341!1m5!1m1!1s0x8096ec19d6e11e07:0xff3d200ee1998995!2m2!1d-119.677369!2d37.7156842!1m5!1m1!1s0x8096f3ac1cc0216d:0xefce844b7e66aabf!2m2!1d-119.5516341!2d37.7260607!1m5!1m1!1s0x8096f3cef6f808d5:0x8d88065195e1bad5!2m2!1d-119.5494208!2d37.7477377!1m5!1m1!1s0x8096f201821a2077:0x1828a646b2b40e4e!2m2!1d-119.5963794!2d37.7482139!1m5!1m1!1s0x8091425ee20ea651:0xd0a3b52d5a89e8f!2m2!1d-120.5015525!2d37.3021635!3e0">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/californie_jour_7.png" alt="Itinéraire jour 7"/>
</a>
</p>
<p>On se réveille le septième jour en découvrant la température extérieure :
20°F ! On n’a jamais vu un chiffre aussi bas en fahrenheit, et on est un peu
perdu dans la conversion. On finit par découvrir que ça fait -7°C ! Et oui,
Mammoth Lakes est une station de ski et on est passé de -85m d’altitude à
2400m ! On pensera à vérifier les altitudes pour la prochaine fois…</p>
<p>On part donc pour <a href="https://www.nps.gov/yose/index.htm">Yosemite National
Park</a>, notre parc national de la journée.
En chemin, on s’arrête au bord du <a href="https://fr.wikipedia.org/wiki/Lac_Mono">Lac
Mono</a>, en prenant la route 120 à
l’est. Il y a une petite balade tranquille d’une petite heure, au départ de
<a href="http://www.openstreetmap.org/way/24815287#map=19/37.93869/-119.02681">ce
parking</a>.
On y est allé vers 9h le matin, on a pu faire le tour sans croiser personne,
et en voyant pleins de <a href="https://fr.wikipedia.org/wiki/Tamia">tamias</a>,
d’oiseaux et de lapins sur le bord du chemin. Il faut payer quelques dollars
pour ce parc, mais il n’y avait aucun <em>ranger</em> au guichet (ils arrivaient
quand on est reparti je crois), et on n’a pas trouvé comment régler notre dû.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05533.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05533.JPG" alt="Lac Mono" />
</a>
</p>
<p><em>Info pratique :</em> Pour Yosemite, comme pour la Vallée de la mort, repérez bien
votre itinéraire et vos arrêts à l’avance et ne comptez pas trop sur votre
téléphone. On n’a quasiment jamais eu de réseau entre <a href="http://www.openstreetmap.org/node/1343514149">le col
Tioga</a> et loin après la sortie
de la vallée, à
<a href="http://www.openstreetmap.org/way/33207307#map=14/37.4821/-119.9676">Mariposa</a>.</p>
<p>On repart sur la 120 vers l’ouest (Tioga Pass Road), direction Yosemite. Cette
route est magnifique, avec de nombreux arrêts et points de vue sur le côté. On
passe plein de montagnes, de vues et de lacs superbes, on traverse <a href="https://fr.wikipedia.org/wiki/Tuolumne_Meadows">Tuolumne
Meadows</a> et on passe le col
Tioga à 3031m (sûrement le point le plus haut du voyage). C’est sur cette
route qu’on paye aussi l’accès à Yosemite. Comme d’habitude, 30$ par véhicule,
valable une semaine, ou un pass (voir le Grand Canyon). On récupère aussi <a href="https://www.nps.gov/yose/planyourvisit/maps.htm">une
carte</a>.</p>
<p><em>Info pratique :</em> La route 120 (Tioga Pass Road) ferme vers la fin de
l’automne. On a pu y passer, mais c’était une des dernières semaines où elle
était ouverte. Si elle est fermée, il faut faire tout le tour par le nord, et
ça prend bien 4h.</p>
<p>Premier arrêt dans la vallée de Yosemite : <a href="https://www.yosemitehikes.com/tioga-road/tuolumne-grove/tuolumne-grove.htm">Tuolumne
Grove</a>
pour voir des séquoias géants ! On ne pouvait pas passer au <a href="https://www.nps.gov/seki/index.htm">Sequoia National
Park</a> et <a href="https://www.nps.gov/yose/planyourvisit/mg.htm">Mariposa
Grove</a> était fermé pour
restauration, donc on s’est rabattu sur Tuolumne Grove pour voir des séquoias
géants. On n’a pas regretté ! C’était top, on peut voir de nombreux séquoias
géants, dont plusieurs en bonne santé, un (mort) qu’on peut traverser avec un
tunnel, et un autre (qui s’est déraciné récemment) couché à terre qu’on peut
donc voir de très près. Compter une heure de balade.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05559.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05559.JPG" alt="Tuolumne Grove" />
</a>
</p>
<p>On continue sur la route et on s’arrête à <a href="https://www.nps.gov/yose/planyourvisit/bridalveilfalltrail.htm">Bridalveil
Fall</a>, une
cascade accessible en 10 minutes de marche, puis on monte à <a href="https://fr.wikipedia.org/wiki/Tunnel_View">Tunnel
View</a>, un splendide point de vue
sur la vallée (notamment sur El Capitan et le Half Dome), sur la route qui
mène à <a href="https://fr.wikipedia.org/wiki/Glacier_Point">Glacier Point</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05570.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05570.JPG" alt="Tunnel View" />
</a>
</p>
<p>Là, grosse hésitation pour savoir si on continue sur la route de Glacier
Point (mais dans ce cas, on ne fera quasiment que ça de l’après-midi, il faut
bien 1h30 aller-retour), si on se lance dans le <a href="https://www.yosemitehikes.com/yosemite-valley/four-mile-trail/four-mile-trail.htm">Four-Mile
trail</a>
(mais c’est trop juste en temps et pas très raisonnable) ou si on redescend
dans la vallée. Finalement, on opte pour redescendre dans la vallée et on ne
le regrettera pas. On note quand même de revenir pour faire le Four-Mile trail.</p>
<p>On redescend donc dans la vallée et regarde les balades moyennes, d’une heure
environ. On hésite entre deux, et on aura le temps de faire les deux
finalement :)</p>
<p>Les deux balades ne sont pas accessibles directement en voiture. Il faut se
garer quelque part et prendre la navette gratuite, qui nous y pose. La navette
tourne régulièrement et on l’a très peu attendue, pour ça c’était top.</p>
<p>Première balade à <a href="https://www.yosemitehikes.com/yosemite-valley/vernal-fall-footbridge/vernal-fall.htm">Vernall Fall
Footbridge</a>,
compter une petite heure si vous êtes un peu sportifs (attention, ça monte).
On arrive au pied de la cascade Vernall, et les panoramas sont superbes.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05586.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05586.JPG" alt="Vernall Fall" />
</a>
</p>
<p>Deuxième balade à <a href="https://www.nps.gov/yose/planyourvisit/mirrorlaketrail.htm">Mirror
Lake</a>. La balade
est beaucoup plus facile que la précédente, essentiellement sur du plat et
très carrossable. Mirror Lake est un lac saisonnier. Il n’y avait pas d’eau
mi-octobre, mais les panoramas étaient encore une fois superbes. Ça doit être
encore mieux quand le lac est rempli !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05620.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05620.JPG" alt="Mirror Lake" />
</a>
</p>
<p><em>Info pratique :</em> Attention aux unités, les distances américaines pour les
randos sont affichées en milles (et quelques fois en kilomètres). On marche à
4km/h, mais ça ne fait que 2 milles par heure. :) On a vu quelques fois aussi
des distances pour l’aller-retour, mais la durée affichée à côté pour l’aller
simple, ou l’inverse.</p>
<p>Finalement, on va voir les <a href="https://www.nps.gov/yose/planyourvisit/lowerfalltrail.htm">Lower Yosemite
Falls</a> et on
regarde le soleil se coucher derrière Glacier Point avant de repartir pour
<a href="http://www.openstreetmap.org/relation/112291">Merced</a>, où on passe la nuit.</p>
<p>Merced n’a pas très bonne réputation (32% de la population vit sous le seuil
de pauvreté), mais a l’avantage d’être à proximité de Yosemite et sur
l’autoroute pour San Francisco. De toutes façons, on y arrive tard et on va
juste y dormir. On mange dans un Burger King le long de l’autoroute (après
s’être perdu au milieu de parkings glauques), et on dort à l’<a href="https://fr.redlion.com/merced">Americas Best
Value Inn</a>, un motel très bien situé le long de
l’autoroute. Le quartier n’est pas terrible, vraiment pas très sûr, mais
l’enceinte de l’hôtel est très sûre et l’hôtel est en travaux donc les
chambres sont toutes neuves. On est proche de l’autoroute, donc ça ne fait pas
un gros détour, et le tout pour un prix plus qu’abordable !</p>
<p>La carte du trajet de la journée est
<a href="https://www.google.fr/maps/dir/Motel+6+Mammoth+Lakes/Mono+lake+-+South+Tufa+Area/Tioga+Pass+Rd,+California/Tuolumne+Grove+Trailhead/Bridalveil+Fall+Viewing+Point/Tunnel+View/Vernal+Falls+Bridge,Yosemite+Village/Mirror+Lake/Lower+Yosemite+Fall+Trail/Americas+Best+Value+Inn+Merced/@37.6236534,-120.2692213,9z/data=!3m1!4b1!4m62!4m61!1m5!1m1!1s0x80960dc9646c4d91:0x3ce9d42ff47ca4ca!2m2!1d-118.972519!2d37.649113!1m5!1m1!1s0x8096388a4a162e19:0x4f111f0afdedb852!2m2!1d-119.0269924!2d37.9386734!1m5!1m1!1s0x8096f7835559cfc3:0xf13f8b5f454d862f!2m2!1d-119.4454537!2d37.8472262!1m5!1m1!1s0x8096c2b0ba302b5d:0x334dfa09f120a1ec!2m2!1d-119.805421!2d37.7581939!1m5!1m1!1s0x8096ec3a87498f41:0x616838fc29f68fa8!2m2!1d-119.647734!2d37.7169341!1m5!1m1!1s0x8096ec19d6e11e07:0xff3d200ee1998995!2m2!1d-119.677369!2d37.7156842!1m5!1m1!1s0x8096f3ac1cc0216d:0xefce844b7e66aabf!2m2!1d-119.5516341!2d37.7260607!1m5!1m1!1s0x8096f3cef6f808d5:0x8d88065195e1bad5!2m2!1d-119.5494208!2d37.7477377!1m5!1m1!1s0x8096f201821a2077:0x1828a646b2b40e4e!2m2!1d-119.5963794!2d37.7482139!1m5!1m1!1s0x8091425ee20ea651:0xd0a3b52d5a89e8f!2m2!1d-120.5015525!2d37.3021635!3e0">ici</a>
(chez Google cette fois-ci, OpenStreetMap a du mal à tracer l’itinéraire dans
la vallée de Yosemite :/).</p>
<h2>Jour 8 : Retour à San Francisco (250km, 3h)</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=37.441064&n2=-121.436005&n3=9&a=37.331751,-120.472344,37.921993,-122.348557,37.875123,-122.517825,37.82016,-122.478746,37.802927,-122.448402,37.780165,-122.514068,37.807134,-122.405022&b=0&c=0&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/californie_jour_8.png" alt="Itinéraire jour 8"/>
</a>
</p>
<p>Avant-dernier jour et retour à San Francisco. On passe par le nord de la baie,
pour voir (de loin)
<a href="https://fr.wikipedia.org/wiki/Oakland_(Californie)">Oakland</a>,
<a href="https://fr.wikipedia.org/wiki/Berkeley_(Californie)">Berkeley</a> et on s’arrête
à <a href="https://fr.wikipedia.org/wiki/Sausalito_(Californie)">Sausalito</a> en fin de
matinée. Le pont qui traverse la baie de San Francisco sur la 580 au nord est
payant, et il faut forcément payer en cash (si on n’a pas l’équivalent du télépéage).</p>
<p>À Sausalito, on trouve <a href="https://www.google.fr/maps/place/Lot+%235/@37.8602915,-122.4868648,19.25z/data=!4m13!1m7!3m6!1s0x8085845331c92675:0xb903aa6d828f51ee!2sSausalito,+Californie+94965,+%C3%89tats-Unis!3b1!8m2!3d37.8590937!4d-122.4852507!3m4!1s0x80858451564b6f83:0x8c3fac367c6c611d!8m2!3d37.8605783!4d-122.4862417">une place de
parking</a>
bien située et gratuite jusqu’à trois heures, sur un parking étonnement vide
sachant que tous les stationnements autour sont payants. On remonte ensuite
vers le port pour voir les <a href="http://www.oursausalito.com/houseboats/houseboats-in-sausalito.html">maisons
flottantes</a>
et profiter de la vue sur la baie. Le midi, on prend un brunch au <a href="http://www.oursausalito.com/restaurants-best/restaurants-best-lunch-only/lighthouse-cafe.html">Lighthouse
Café</a>
avec d’énormes et délicieux pancakes !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05667.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05667.JPG" alt="Taj Mahal" />
</a>
</p>
<p>On reprend ensuite la route direction le <a href="https://fr.wikipedia.org/wiki/Pont_du_Golden_Gate">Golden
Gate</a>, en particulier le
<a href="http://www.openstreetmap.org/node/1183476394">point de vue</a> avant le pont.
Attention, il y a peu de parking et beaucoup de touristes !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05680.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05680.JPG" alt="Golden Gate" />
</a>
</p>
<p>Le passage du Golden Gate en voiture est payant et on reçoit une facture
automatiquement par lecture de la plaque d’immatriculation. Du coup, le plus
simple est sûrement de payer avant son passage, sur <a href="http://goldengate.org/tolls/">leur
site</a>.</p>
<p>De l’autre côté, on s’arrête <a href="http://www.openstreetmap.org/way/91814413">à côté du centre des
visiteurs</a> (parking à 1$ de
l’heure, étonnement peu cher), puis on va faire un tour à pied sur le Golden
Gate avant de descendre à <a href="http://www.openstreetmap.org/node/4970567036">Fort
Point</a>, sous le pont. On l’a
découvert trop tard, mais le <a href="http://www.openstreetmap.org/way/370505354">parking devant le
fort</a> semble être accessible à
tous en voiture et gratuit.</p>
<p>On passe ensuite en voiture au <a href="http://www.openstreetmap.org/way/288371295#map=19/37.80292/-122.44839">Palace of Fine
Arts</a>
(beaucoup trop de monde pour trouver une place de parking), où l’on croise
notre première voiture autonome ! Puis on va voir les <a href="https://fr.wikipedia.org/wiki/Sutro_Baths">Sutro
Baths</a> et l’océan Pacifique à
<a href="https://en.wikipedia.org/wiki/Lands_End_(San_Francisco)">Lands End</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05692.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05692.JPG" alt="Sutro Baths" />
</a>
</p>
<p>On avait prévu une visite d’Alcatraz de nuit (dernier tour de la journée, à
18h30). Pour garer la voiture, le meilleur plan semble être vers <a href="https://unionsquareshop.com/parking.html">Union
Square</a> (parkings fermés et
sécurisés, prix raisonnables en soirée). Les parkings vers les quais sont hors
de prix et à San Francisco il vaut mieux se garer dans un parking fermé et
surveillé, vu le nombre de vols dans les voitures.</p>
<p>N’ayant pas encore pu prendre la <em>cable car</em>, on prend la ligne sur Powell et
Hyde pour rejoindre le front de mer et l’embarcadère pour Alcatraz (Pier 33).
Pour prendre une <em>cable car</em>, on regarde <a href="http://d139u8doh717eh.cloudfront.net/cable-car-map-san-francisco.pdf">une
carte</a>,
puis on essaye de déterminer un arrêt et on attend. Puis on paye directement
au conducteur (7$ l’aller simple). Les <em>cable car</em> partent tous <a href="http://www.openstreetmap.org/way/197974389">du bout de
Powell St</a>, mais il y a une file
d’attente interminable à cet endroit (plus d’une heure je pense). En pratique,
les <em>cable car</em> ne partent jamais pleines, et on peut en prendre une sans
attendre en marchant un ou deux arrêts. Par contre, on n’a pas forcément la
meilleure place.</p>
<p>À Alcatraz, la visite de nuit nous laisse un peu plus de deux heures sur
l’île. On visite le bâtiment principal de la prison, on profite de la
magnifique vue sur la baie de nuit. On profite aussi d’un couloir de prison en
plus (habituellement fermé) et de quelques présentations et animations
(animées par des <em>rangers</em>, sur la vie de certains prisonniers ou des
démonstrations d’ouverture de portes) en plus. Un énorme avantage de faire la
dernière visite de la journée c’est qu’on fait la fermeture du site et qu’on
peut donc prendre des photos des lieux déserts, sans personne ! Je pense qu’on
ne voit pas tout à fait la même chose que de jour (mais je ne peux pas
comparer), notamment les jardins. En tout cas c’était top et on ne regrette
pas !</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05817.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05817.JPG" alt="Alcatraz" />
</a>
</p>
<p><em>Note :</em> Quand on prend un billet pour Alcatraz, on prend un billet pour un
horaire donné et une visite qui dure un certain temps. En pratique, on est
obligé de prendre le ferry à l’horaire prévu pour aller sur l’île, mais la
visite se fait en autonomie et je n’ai pas eu l’impression qu’il y ait le
moindre contrôle du ferry par lequel on rentrait. On peut donc a priori rester
toute la journée sur l’île (après, c’était peut-être particulier parce qu’on
prenait les derniers ferries de la journée).</p>
<p>Le soir, on découvre les tarifs étonnants du McDo (4.99$ les 10 nuggets de
poulet, 5$ les 20) puis on file à <a href="https://fr.wikipedia.org/wiki/Mountain_View_(Californie)">Mountain
View</a> où on dort
chez un pote.</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=37.441064&n2=-121.436005&n3=9&a=37.331751,-120.472344,37.921993,-122.348557,37.875123,-122.517825,37.82016,-122.478746,37.802927,-122.448402,37.780165,-122.514068,37.807134,-122.405022&b=0&c=0&k1=en-US&k2=km">ici</a>.</p>
<h2>Jour 9 : Silicon Valley</h2>
<p style="text-align: center">
<a href="https://openrouteservice.org/directions?n1=37.404324&n2=-122.088232&n3=13&a=37.430545,-122.169013,37.380907,-122.087021,37.413795,-122.058012,37.414372,-122.077353,37.422267,-122.083824&b=0&c=0&k1=en-US&k2=km">
<img style="width: 75%"
src="http://localhost/Blog/output/images/2017/11/californie_jour_9.png" alt="Itinéraire jour 9"/>
</a>
</p>
<p>Dernier jour de ce voyage, dans la Silicon Valley. On va faire un tour sur le
campus de <a href="https://fr.wikipedia.org/wiki/Université_Stanford">Stanford</a>, puis
dans le centre-ville de Mountain View, avant d’aller voir le centre de la
<a href="https://www.nasa.gov/ames"><span class="caps">NASA</span></a> et le
<a href="https://fr.wikipedia.org/wiki/Googleplex">Googleplex</a>.</p>
<p style="text-align: center">
<a href="http://localhost/Blog/output/images/2017/11/californie/DSC05818.JPG">
<img style="width: 50%"
src="http://localhost/Blog/output/images/2017/11/californie/DSC05818.JPG" alt="Stanford" />
</a>
</p>
<p>On finit la journée au <a href="http://www.computerhistory.org/">musée de l’histoire de
l’ordinateur</a>. Attention, le musée ferme tôt
(17h) et est assez long, mais très intéressant (et assez dense). Il y a des
billets à tarifs très avantageux chez
<a href="https://www.groupon.com/deals/computer-history-museum-3">Groupon</a>.</p>
<p>Le soir, direction l’aéroport pour prendre notre vol, où l’on se rend compte
qu’avec le décalage horaire, notre vol de 7h ne dure que 4h en réalité, et
qu’on ne dormira pas de la nuit :/ On découvre ce que veut dire <em>red-eye
flight</em> sur notre billet :)</p>
<p>La carte du trajet de la journée est
<a href="https://openrouteservice.org/directions?n1=37.404324&n2=-122.088232&n3=13&a=37.430545,-122.169013,37.380907,-122.087021,37.413795,-122.058012,37.414372,-122.077353,37.422267,-122.083824&b=0&c=0&k1=en-US&k2=km">ici</a>.</p>
<h2>Quelques notes</h2>
<ul>
<li>Tous les liens vers Wikipedia que j’ai utilisés dans cet article renvoient
vers la version française du site (si disponible) ou la version anglaise (à
défaut). Si vous le pouvez, il vaut mieux lire tous les articles sur la
version anglaise, qui est beaucoup plus fournie :)</li>
<li>Aux États-Unis, les prix sont en général sans service et sans taxes. Bon à
savoir pour ne pas oublier d’inclure les presque 20% de taxes sur les
chambres d’hôtel à certains endroits, et les (environ) 8% de taxes et 18%
de <em>tip</em> de rigueur au restaurant. Au restaurant, il faut donc compter
environ 25% de plus que le tarif affiché sur la carte.</li>
<li>L’art du <em>tip</em> est très dur à maîtriser. Visiblement, on donne un pourboire
au coiffeur, mais pas au taxi (alors que les taxis réclament souvent). Bref,
on prend un <span class="caps">VTC</span> qui nous évite de nous poser la question :p On donne un
pourboire au restaurant, entre 18% et 20% avant les taxes, mais pas si on
prend à emporter. Pourtant, il est souvent proposé de laisser un pourboire
quand on prend à emporter ! ><</li>
<li>On a fait l’erreur (ou pas) de se dépêcher de prendre nos billets d’avion,
et pour Alcatraz (car il faut s’y prendre très à l’avance), avant d’avoir
planifié le reste du voyage. C’est passé, mais rétrospectivement, ça aurait
sûrement été plus simple et pas beaucoup plus cher d’arriver à Las Vegas et
de repartir de San Francisco, sans faire de vol dans la semaine ; ou de
visiter Alcatraz en début de semaine pour ne pas avoir d’impératif fixe en
fin de semaine.</li>
</ul>
<h3>Sur San Francisco</h3>
<ul>
<li>Les transports publics sont assez chers. Pour peu qu’on soit deux ou trois,
il est parfois plus avantageux de prendre un Uber (pool) ou un Lyft (line).</li>
<li>Les hôtels et auberges de jeunesse sont assez chers. Les hébergements
meilleur marché n’ont souvent pas de très bons commentaires (saleté,
punaises de lit, etc.), ou sont situés dans des quartiers connus pour ne pas
être très sûrs de nuit (Tenderloin notamment, même si en plein
centre ville).</li>
</ul>
<h3>Sur Las Vegas</h3>
<ul>
<li>Là, c’est le contraire, il y a tellement d’hôtels qu’ils sont à des prix
très abordables. Attention à bien prendre en compte les taxes et autres
suppléments (<em>resort fees</em>) qui sont à payer en plus de la chambre d’hôtel
et rarement inclus sur les tarifs affichés. Il y a de très bons plans de
temps en temps. Dans notre cas, une nuit un dimanche soir au Trump hotel (5
étoiles) nous a coûté 100€, contre plus de 300€ en milieu de semaine.</li>
<li>Les hôtels sont souvent assez hauts, et vous aurez donc souvent
une chambre dite “avec vue”. Par contre, vous serez rarement orientés du
côté du Strip (surtout pour les chambres les moins chères), et il ne faut
donc pas espérer avoir une vue incroyable. :)</li>
<li>À Las Vegas (et peut être ailleurs), on vous proposera toujours de payer un
supplément à votre arrivée pour avoir une meilleure chambre. En pratique,
nos chambres étaient toujours les moins chères et toujours très bien. :)</li>
</ul>
<h2>Quelques jours de plus</h2>
<p>Avoir quelques jours en plus aurait été bien pratique et plus reposant.
Voici quelques idées de changements si c’est votre cas :</p>
<ul>
<li>Être plus tranquille pour faire le trajet de Las Vegas à Page (surtout si on
a un accident…). Avoir une journée de plus à ce moment permet non seulement
de s’arrêter à <a href="https://www.nps.gov/brca/index.htm">Bryce Canyon National
Park</a>, à <a href="http://parks.nv.gov/parks/valley-of-fire">Valley of Fire National
Park</a> ou encore à <a href="https://www.nps.gov/zion/index.htm">Zion National
Park</a>, mais aussi de faire la visite
d’Antelope Canyon le matin, au moment où la lumière est la mieux.</li>
<li>Il paraît que <a href="https://en.wikipedia.org/wiki/Downtown_Las_Vegas">le centre-ville de Las
Vegas</a> est très sympa
aussi, avec des spectacles de rue. On n’a pas eu le temps d’aller voir malheureusement.</li>
<li>À l’est de Flagstaff, il y a un <a href="https://fr.wikipedia.org/wiki/Meteor_Crater">cratère de
météorite</a> qui a l’air très impressionnant.</li>
<li>Un jour de plus à Yosemite aurait été très confortable et nous aurait permis
de faire le Four-Mile trail et plus de balades dans ce magnifique parc national.</li>
<li>Un jour de plus à San Francisco pour faire quelques musées, notamment le
<a href="https://www.sfmoma.org/"><span class="caps">SFMOMA</span></a>.</li>
</ul>
<h2>Quelques références</h2>
<ul>
<li>Le blog de <a href="https://www.maathiildee.com/">Mathilde</a>, une française installée
à Boston et qui écrit beaucoup sur ses <em>roadtrips</em>, une super source
d’inspiration !</li>
<li>Concernant Lower Antelope Canyon (et Upper), <a href="http://www.lostintheusa.fr/2015/11/19/upper-ou-lower-antelope-canyon-lequel-choisir/">cet
article</a>
était très pratique :)</li>
<li>Pour savoir à quel moment il vaut mieux aller voir Horseshoe Bend, je vous
laisse <a href="https://horseshoebend.com/brian-klimowski-photography-tips-from-the-pros/">vous faire une
idée</a>.</li>
<li>Pour se garer à San Francisco, il y a <a href="https://www.inside-guide-to-san-francisco-tourism.com/embarcadero-parking.html">ce très bon
guide</a>.</li>
</ul>Don du mois de juillet, août et septembre : Pepper&Carrot, Mastodon et OpenFoodFacts2017-09-26T01:29:00+02:002017-09-26T01:29:00+02:00Phykstag:localhost,2017-09-26:/Blog/output/2017/09/don-du-mois-de-juillet-aout-et-septembre-peppercarrot-mastodon-et-openfoodfacts.html<p>J’ai quelques mois de retard, et ce n’est pas un don mais trois que je
commente dans ce billet, pour les mois de juillet, août et septembre.</p>
<p>Premier don pour <a href="https://www.patreon.com/mastodon">Gargron</a>, le développeur
principal de <a href="https://joinmastodon.org/">Mastodon</a>, ce réseau social libre et
décentralisé, alternative à Twitter. J’ai un …</p><p>J’ai quelques mois de retard, et ce n’est pas un don mais trois que je
commente dans ce billet, pour les mois de juillet, août et septembre.</p>
<p>Premier don pour <a href="https://www.patreon.com/mastodon">Gargron</a>, le développeur
principal de <a href="https://joinmastodon.org/">Mastodon</a>, ce réseau social libre et
décentralisé, alternative à Twitter. J’ai un compte sur l’instance de
<a href="http://mastodon.tetaneutral.net/">Tetaneutral</a> que j’utilise depuis quelques
temps, et j’ai donc donné 15€ au développeur principal pour tout le boulot
incroyable qu’il fournit sur Mastodon, avec de nombreuses versions publiées et
pleins de nouvelles fonctionnalités à chaque fois !</p>
<p>Deuxième don, de 15€ également, pour
<a href="http://openfoodfacts.org/">OpenFoodFacts</a> sur lequel je suis retombé
récemment. Le but d’OpenFoodFacts est de fournir une base de données des
produits alimentaires (mais également <a href="https://world.openbeautyfacts.org/">des produits de
beauté</a> et des <a href="https://world.openpetfoodfacts.org/">aliments pour animaux de
compagnie</a>) sous licence libre (<em>Open
Database License</em>), ainsi que des illustrations sous licence <em>Creative
Commons</em>. Par exemple, <a href="https://fr.openfoodfacts.org/produit/3302745733029/le-batonnet-moelleux-30-batonnets-fleury-michon">un lot de bâtonnets de
surimi</a>
ainsi rentré, avec des indications claires sur les labels présents sur
l’emballage, le lieu de fabrication/transformation, les ingrédients et les
informations nutritionnelles. Les étiquettes deviennent alors beaucoup plus
lisibles, et on peut découvrir que <a href="https://fr.openfoodfacts.org/code-emballeur/fr-35-288-001-ce">le même
emballeur</a>
transforme les yaourts “Malo”, les yaourts “Franprix” et les yaourts
“Pâturages”, entre autres. Il y a aussi une <a href="https://github.com/openfoodfacts/openfoodfacts-androidapp">app
Android</a> sur
<a href="http://fdroid.org/">F-droid</a>, et des apps pour les autres ordiphones.</p>
<p>Enfin, j’ai découvert <a href="https://www.peppercarrot.com/fr/">Pepper&Carrot</a> cet
été, une bande dessinée sous licence <em>Creative Commons <span class="caps">BY</span></em>, réalisée
avec des logiciels libres, et avec des dessins vraiment bluffant. J’ai donc
donné 10€ à <a href="https://www.tipeee.com/pepper-carrot">son auteur</a> après avoir
dévoré tous les épisodes actuellement en ligne :)</p>Two years of Velib data2017-09-08T03:18:00+02:002017-09-08T03:18:00+02:00Phykstag:localhost,2017-09-08:/Blog/output/2017/09/two-years-of-velib-data.html<p>About two years ago, I decided to <a href="https://phyks.me/2015/11/velib-dataset.html">dump on a very regular
basis</a> all the available data
from the Velib <span class="caps">API</span>. Velib is the bike sharing system in Paris, and the <span class="caps">API</span>
exposes a list of stations as well as their respective occupancy (free stands,
available bikes in near realtime …</p><p>About two years ago, I decided to <a href="https://phyks.me/2015/11/velib-dataset.html">dump on a very regular
basis</a> all the available data
from the Velib <span class="caps">API</span>. Velib is the bike sharing system in Paris, and the <span class="caps">API</span>
exposes a list of stations as well as their respective occupancy (free stands,
available bikes in near realtime). I dumped the data every few minutes, and
<a href="https://pub.phyks.me/datasets/velib/">served dumps</a>.</p>
<p>When I started doing it, I did not have any particular project in mind with
this data. I just figured out that historical data was not available through
the <span class="caps">API</span> (only realtime data is available), and that it might be useful for
users to make some statistical analysis on nearby stations, for instance.</p>
<p>I recently had the idea of visualizing Velib data superimposed on a map of
Paris and <a href="https://github.com/Phyks/VelibDataSet/blob/master/visu.py">coded a small script to render the images from my
dataset</a>.</p>
<p>The idea is to draw a <a href="https://en.wikipedia.org/wiki/Voronoi_diagram">Voronoi
diagram</a> based on the position
of Velib stations and superimposed it on a map of Paris. This would provide a
tiling on top of Paris, where each tile can be thought of as the area of
influence of a given station. Then, I colored the tiles on a red to green
scale, depending on the bike availability.</p>
<p>If you are curious about what it looks like, here is <a href="https://www.youtube.com/watch?v=5r1ldkm1rzo">one year of Velib
starting from 09/11/2015</a> and
<a href="https://www.youtube.com/watch?v=7YUsEdqy5Zg">(nearly) one year of Velib starting from
10/11/2016</a>. It is quite
surprising that we can really see recurring patterns in the video, I was
actually not hoping it would be so clear! :)</p>
<p>Many things could still be improved, such as the colorscale which would be
better if I exchanged red and green, or the resolution of the generated
images, but this is a quick and dirty proof of concept :) My code is far from
being optimized and it took about 30 hours to output all the necessary images
(one image per 5 minutes) from the dumped <span class="caps">SQL</span> database.</p>
<p><em>Note</em>: If you build anything from the datasets or make a better render of my
maps, feel free to shoot me an email about it, I would be really interested in
what people are building with all this!</p>Looking for a flat the modern way2017-08-06T20:03:00+02:002017-08-06T20:03:00+02:00Phykstag:localhost,2017-08-06:/Blog/output/2017/08/looking-for-a-flat-the-modern-way.html<p>I recently moved home and had to go through the painful process of looking for
a new flat to rent. You usually want to optimize various criteria, such as the
commuting time, but housing websites and their search form are not fit for
these. You also end up doing a …</p><p>I recently moved home and had to go through the painful process of looking for
a new flat to rent. You usually want to optimize various criteria, such as the
commuting time, but housing websites and their search form are not fit for
these. You also end up doing a lot of deduplication manually between multiple
housing websites. Plus you want to crawl the websites as often as possible as
in large cities such as Paris interesting posts only stay a couple of hours online.</p>
<p>Most people just crawl the housing posts websites regularly, manually, to look
for the perfect flat. These include <a href="http://leboncoin.fr/">Leboncoin</a> (French
equivalent to <a href="http://craigslist.org/">Craigslist</a>),
<a href="http://seloger.com/">SeLoger</a> (a website centralizing posts from real-estate
agencies), <a href="http://www.pap.fr/">Pap</a> (similar to Craigslist, but focused on
housing) and many many real-estate agencies websites. This is a really painful
process as there are a lot of duplicate posts to filter by hand and they tend
to return broader results than you asked for (typically, including results
with a location close to the asked locations, or flats with slightly smaller areas).</p>
<p>I was going to do this manual crawling process, when I realized
<a href="http://weboob.org/">Weboob</a> actually has modules for a bunch of these websites!</p>
<p>Weboob, Web Outside Of Browsers, is a Python tool which can be used to scrap
websites and fetch info from them, from weather info to housing posts. I could
then just use it to fetch all the available posts from the websites, and make
a <span class="caps">JSON</span> export. From this building block, I could build a tool to help me (and
you!) find a new place: let me introduce you
<a href="https://git.phyks.me/Phyks/flatisfy">Flatisfy</a>!</p>
<p>Flatisfy is a Python tool made of:
- a backend to fetch, filter out housing posts according to some criteria and
“augment” the results with new machine-readable metadata found by analyzing
the post, such as postal code, nearby public transport stations and travel
time to specific place.
- a frontend which is just a web app to explore the results, usable with any
regular browser.</p>
<p><em>Disclaimer</em>: This tool is focused on France, and in particular Paris and Lyon
(it has been successfully used there). It may not work directly with other
places, but should be customizable enough to do the job.</p>
<p><em>Note</em>: Throughout this post, I use the word “flat”. It should be considered
as a synonym to housing, as Flatisfy should also work if you look for a house.</p>
<h2>Too long, didn’t read, show me pictures!</h2>
<p>Ok, here are some screenshots. Note that the <span class="caps">UI</span> might change a lot in the near
future, this is basically just a proof of concept.</p>
<h3>Home page</h3>
<p>Home page shows a map of found flats and places you are interested in, and a
table showing the complete list of flats by postal codes.</p>
<p style="text-align: center;">
<img style="width: 45%;" src="http://localhost/Blog/output/images/2017/08/flatisfy/home.png"
alt="Homepage" />
<img style="width: 45%;"
src="http://localhost/Blog/output/images/2017/08/flatisfy/home2.png" alt="Homepage 2" />
</p>
<h3>Details page</h3>
<p>For each flat, the details page shows all the available details in a uniform
way. No more searching through ugly websites to find some piece of information
you have on another website, everything is rendered the same, for easy comparison!</p>
<p style="text-align: center;">
<img style="width: 75%;"
src="http://localhost/Blog/output/images/2017/08/flatisfy/details.png"
alt="Details of a flat" />
</p>
<h3>Tracking and annotating flats</h3>
<p>You can annotate flats of interest, to easily sort them and manage a “to
contact first” list:)</p>
<p style="text-align: center;">
<img style="width: 75%;"
src="http://localhost/Blog/output/images/2017/08/flatisfy/followed.png"
alt="Follow and annotate flats" />
</p>
<h2>Sounds nice, how do I try it?</h2>
<p>You can have a look at <a href="https://git.phyks.me/Phyks/flatisfy/blob/master/doc/0.getting_started.md">the getting started
doc</a>
to get started quickly with a manual installation. A <a href="https://git.phyks.me/Phyks/flatisfy/blob/master/doc/2.docker.md">docker
image</a> is
also available to test Flatisfy.</p>
<h2>How does it work?</h2>
<p>Flatisfy is basically a super-wrapper on top of Weboob. It is using Weboob to
fetch info, and post-process them afterwards. There are three filtering passes
implemented for now.</p>
<p>First pass removes obvious duplicates (same <span class="caps">URL</span> or same <span class="caps">ID</span>) from the list of
fetched flats. Then, it tries to match a postal code and eventually some
public transport stations from the text fields (<code>location</code> and <code>stations</code>)
provided by Weboob. Finally, it does a gross refine of the flats list based on
your criterias (remove flats with are obviously out of your lookup zone, or
too expensive, or too small for instance), as housing websites tend to return
broader results than you asked for.</p>
<p>This first pass aims at doing a basic filtering from the “results” page of the
housing websites, in order to limit the number of queries to get detailed
informations about each flat that might match.</p>
<p>Using the additional details loaded for each flat, second pass tries to
confirm previously guessed infos such as postal code and stations. Then, for
flats having matched public transport stations, it computes the travel time to
location you defined in your config, and further filter flats according to
your criteria.</p>
<p>Finally, third pass is a deep duplicate detection pass. It tries to fetch
duplicates across websites, and to automatize what you used to do manually. It
compares price, area and photos of posts to merge duplicates together.</p>
<h2>What about the future?</h2>
<p>Flatisfy is currently in a working state and can already be used. Actually, it
was successfully used a couple of times already, to find either a place to
rent or a place to buy.</p>
<p>If you don’t live in Paris or Lyon, you might have to import extra data to
benefit from all the advanced features. This is quite easy to do if your city
provides opendata. Please, fill in a merge request with the extra data, so
that it could benefit to everyone! :)</p>
<p>I already have <a href="https://git.phyks.me/Phyks/flatisfy/issues?label_name%5B%5D=ideas">some
ideas</a> for
the future, mainly comparing prices with prices nearby, providing an <span class="caps">ICS</span> feed
automatically generated from visits schedules and a better and more responsive
web <span class="caps">UI</span>. :)</p>Tracking your bank accounts with a Raspberry Pi: Kresus2017-07-24T19:42:00+02:002017-07-24T19:42:00+02:00Phykstag:localhost,2017-07-24:/Blog/output/2017/07/tracking-your-bank-accounts-with-a-raspberry-pi-kresus.html<p>I always had troubles tracking expenses on my bank accounts. You never have
the correct password or login when you want to check your bank account status,
you have to log into every bank website when you have multiple bank accounts,
bank interfaces are super painful and so on. I …</p><p>I always had troubles tracking expenses on my bank accounts. You never have
the correct password or login when you want to check your bank account status,
you have to log into every bank website when you have multiple bank accounts,
bank interfaces are super painful and so on. I recently discovered
<a href="https://kresus.org/">Kresus</a>, a nice app to selfhost on one of your servers
and centralize in a single <a href="https://demo.kresus.org/">interface</a> all your bank
accounts, while offering advanced features to ease tracking expenses. For
instance you can enter check expenses when you are making the check, and this
“virtual” transaction can be merged with the real transaction when the check
is taken to the bank, thus ending “Check number <span class="caps">XXX</span>” unknown transactions on
your operations list.</p>
<p>As I consider banking information very sensitive, I decided to host the app on
a dedicated Raspberry Pi on my local network, quite isolated and controlled. I
am assuming you start with a lite version of <code>Raspbian</code>. You can have a look
at my <a href="https://phyks.me/2017/02/raspberry-pi-install-checklist.html#raspberry-pi-install-checklist">Raspberry pi post-install
checklist</a>.</p>
<p><em>Note</em>: This post is about a quite cutting-edge setup, using <code>nightly</code>
versions of Kresus (instead of stable tagged versions) and Python 3 instead of
Python 2. Python 3 support is still very experimental as of writing this
blogpost, but the instructions should work by cloning a git tag of Kresus
(instead of using the <code>master</code> branch) and replacing <code>python3</code> by <code>python2</code>.</p>
<h2>Install NodeJS</h2>
<p>First, you should install <code>NodeJS</code>. <code>NodeJS</code> is sadly only available in a very
old version in <code>Raspbian</code> repositories, and <code>NodeJS</code> official repositories and
install script does not yet support the <span class="caps">ARM</span> platform, so you will have to
install it by hand.</p>
<p>The easiest way to get it is to <code>wget</code> the <span class="caps">LTS</span> version available on <a href="https://nodejs.org/en/">the
official website</a> on your Raspberry Pi (take care in
downloading the correct <span class="caps">ARM</span> build) and inflating it to <code>/usr</code>. As of writing
this blog post, this can be done with</p>
<div class="highlight"><pre><span></span><code>pi@raspberry<span class="w"> </span>~<span class="w"> </span>$<span class="w"> </span>wget<span class="w"> </span>https://nodejs.org/dist/v6.11.1/node-v6.11.1-linux-armv6l.tar.xz
pi@raspberry<span class="w"> </span>~<span class="w"> </span>$<span class="w"> </span>tar<span class="w"> </span>xvf<span class="w"> </span>node-v6.11.1-linux-armv6l.tar.xz
pi@raspberry<span class="w"> </span>~<span class="w"> </span>$<span class="w"> </span>sudo<span class="w"> </span>cp<span class="w"> </span>-R<span class="w"> </span>node-v6.11.1-linux-armv6l/*<span class="w"> </span>/usr/
pi@raspberry<span class="w"> </span>~<span class="w"> </span>$<span class="w"> </span>rm<span class="w"> </span>-r<span class="w"> </span>node-v6.11.1-linux-armv6l*
</code></pre></div>
<p>If everything went smoothly, <code>node</code> and <code>npm</code> commands should be available.</p>
<h2>Install Weboob</h2>
<p><a href="http://weboob.org/">Weboob</a> is a dependency of Kresus, it is the free
software powering the backend and actually fetching data from your bank
website. You should install it before installing Kresus.</p>
<p>First, install Weboob dependencies:</p>
<div class="highlight"><pre><span></span><code>pi@raspberry<span class="w"> </span>~<span class="w"> </span>$<span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>update<span class="w"> </span><span class="o">&&</span><span class="w"> </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>git<span class="w"> </span>python3<span class="w"> </span>python3-dev<span class="w"> </span>python3-pip<span class="w"> </span>libffi-dev<span class="w"> </span>libxml2-dev<span class="w"> </span>libxslt-dev<span class="w"> </span>libyaml-dev<span class="w"> </span>libtiff-dev<span class="w"> </span>libjpeg-dev<span class="w"> </span>zlib1g-dev<span class="w"> </span>libfreetype6-dev<span class="w"> </span>libwebp-dev<span class="w"> </span>build-essential<span class="w"> </span>gcc<span class="w"> </span>g++<span class="w"> </span>wget<span class="w"> </span>python3-imaging<span class="w"> </span>python3-lxml
</code></pre></div>
<p>Then, clone the Weboob git repository and install it:</p>
<div class="highlight"><pre><span></span><code>pi@raspberry<span class="w"> </span>~<span class="w"> </span>$<span class="w"> </span>git<span class="w"> </span>clone<span class="w"> </span>https://git.weboob.org/weboob/devel/<span class="w"> </span>weboob
pi@raspberry<span class="w"> </span>~<span class="w"> </span>$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>weboob<span class="w"> </span><span class="o">&&</span><span class="w"> </span>sudo<span class="w"> </span>pip3<span class="w"> </span>install<span class="w"> </span>.
</code></pre></div>
<p>You should <code>cd ~pi/weboob && git pull origin master</code> periodically to ensure
that Weboob modules (the code actually scraping data from your bank website)
are up to date. This is best done in a daily crontask.</p>
<h2>Add a dedicated Kresus user</h2>
<p>Let us add a new user, without password and with <code>/bin/false</code> as shell:</p>
<div class="highlight"><pre><span></span><code>pi@raspberry<span class="w"> </span>~/weboob<span class="w"> </span>$<span class="w"> </span>sudo<span class="w"> </span>adduser<span class="w"> </span>kresus<span class="w"> </span>--disabled-password
pi@raspberry<span class="w"> </span>~/weboob<span class="w"> </span>$<span class="w"> </span>sudo<span class="w"> </span>chsh<span class="w"> </span>kresus
<span class="o">[</span>…<span class="o">]</span><span class="w"> </span>Type<span class="w"> </span><span class="s2">"/bin/false"</span>
</code></pre></div>
<p>This will be the user with restricted privileges that will be used to clone
and run Kresus. To <code>su</code> as this user, use</p>
<div class="highlight"><pre><span></span><code>pi@raspberry<span class="w"> </span>~<span class="w"> </span>$<span class="w"> </span>sudo<span class="w"> </span>su<span class="w"> </span>kresus<span class="w"> </span>-s<span class="w"> </span>/bin/bash
</code></pre></div>
<p><em>Note</em>: When doing a <code>su</code> like this, you cannot use <code>screen</code> afterwards, you
should use <code>script /dev/null</code> before, see <a href="https://serverfault.com/questions/255521/why-does-redirecting-script-to-dev-null-allow-screen-to-work-while-sued-a">this <span class="caps">SO</span>
thread</a>.</p>
<h2>Install Kresus</h2>
<p>We can now clone Kresus Git repository</p>
<div class="highlight"><pre><span></span><code>kresus@raspberry<span class="w"> </span>~<span class="w"> </span>$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span>git<span class="w"> </span>clone<span class="w"> </span>https://framagit.org/kresusapp/kresus/
</code></pre></div>
<p>and install required <span class="caps">NPM</span> packages</p>
<div class="highlight"><pre><span></span><code>kresus@raspberry<span class="w"> </span>~<span class="w"> </span>$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>kresus<span class="w"> </span><span class="o">&&</span><span class="w"> </span>npm<span class="w"> </span>install
</code></pre></div>
<p>This will take quite a long time, especially the <code>pouchdb</code> build as there are
not any prebuilt binary for Raspberry Pi. I had a problem with <code>leveldown</code>
dependency on my Raspberry Pi, it was not installing its dependency <code>prebuild</code>
and build was failing with a <code>prebuild command not found</code> error. If you have
any such issue, just <code>npm install prebuild</code> and re-run <code>npm install</code>.</p>
<p><em>Note</em>: Make sure that as less stuff as possible is running on your Raspberry
Pi when running <code>npm install</code>, or the process might get killed due to an out
of memory error. In case you have a problem with a given module and <code>npm
install</code> does not want to reinstall it, just delete the associated folder
under <code>kresus/node_modules</code> and rerun <code>npm install</code>.</p>
<p>Finally, build the Kresus production files:</p>
<div class="highlight"><pre><span></span><code>kresus@raspberry<span class="w"> </span>~/kresus<span class="w"> </span>$<span class="w"> </span><span class="nv">NODE_ENV</span><span class="o">=</span>production<span class="w"> </span>make<span class="w"> </span>build
</code></pre></div>
<h2>Check that Kresus is working</h2>
<div class="highlight"><pre><span></span><code>kresus@raspberry<span class="w"> </span>/home/kresus/kresus<span class="w"> </span>$<span class="w"> </span><span class="nv">NODE_ENV</span><span class="o">=</span>production<span class="w"> </span><span class="nv">KRESUS_PYTHON_EXEC</span><span class="o">=</span>python3<span class="w"> </span><span class="nv">KRESUS_WEBOOB_DIR</span><span class="o">=</span>/home/pi/weboob<span class="w"> </span>node<span class="w"> </span>bin/kresus.js
</code></pre></div>
<p>It should be starting and giving you access to the web interface on port
<code>9876</code>, giving <code>Kresus server is listening on port 9876...</code> and <code>info - init |
Server is ready, let's start the show!</code> in the logs. Attention, by default
Kresus will not listen on anything else than <code>localhost</code> so you will have to
proxy (typically with <code>ssh</code> <code>SOCKS</code>) on your Raspberry Pi to try it in your browser.</p>
<h2>Launch on start</h2>
<p>Let us use Systemd to start automatically Kresus on boot</p>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">cat</span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">systemd</span><span class="o">/</span><span class="k">system</span><span class="o">/</span><span class="n">kresus</span><span class="p">.</span><span class="n">service</span>
<span class="o">[</span><span class="n">Unit</span><span class="o">]</span>
<span class="n">Description</span><span class="o">=</span><span class="n">Personal</span><span class="w"> </span><span class="n">finance</span><span class="w"> </span><span class="n">manager</span>
<span class="k">After</span><span class="o">=</span><span class="n">network</span><span class="p">.</span><span class="n">target</span>
<span class="o">[</span><span class="n">Service</span><span class="o">]</span>
<span class="n">WorkingDirectory</span><span class="o">=/</span><span class="n">home</span><span class="o">/</span><span class="n">kresus</span><span class="o">/</span><span class="n">kresus</span>
<span class="n">Environment</span><span class="o">=</span><span class="n">NODE_ENV</span><span class="o">=</span><span class="n">production</span>
<span class="n">Environment</span><span class="o">=</span><span class="n">KRESUS_PYTHON_EXEC</span><span class="o">=</span><span class="n">python3</span>
<span class="n">Environment</span><span class="o">=</span><span class="n">KRESUS_WEBOOB_DIR</span><span class="o">=/</span><span class="n">home</span><span class="o">/</span><span class="nf">pi</span><span class="o">/</span><span class="n">weboob</span>
<span class="n">ExecStart</span><span class="o">=/</span><span class="n">usr</span><span class="o">/</span><span class="n">bin</span><span class="o">/</span><span class="n">node</span><span class="w"> </span><span class="n">bin</span><span class="o">/</span><span class="n">kresus</span><span class="p">.</span><span class="n">js</span>
<span class="n">Type</span><span class="o">=</span><span class="n">simple</span>
<span class="n">Restart</span><span class="o">=</span><span class="n">always</span>
<span class="k">User</span><span class="o">=</span><span class="n">kresus</span>
<span class="n">StandardOutput</span><span class="o">=</span><span class="n">journal</span>
<span class="n">StandardError</span><span class="o">=</span><span class="n">inherit</span>
<span class="n">SyslogIdentifier</span><span class="o">=</span><span class="n">kresus</span>
<span class="o">[</span><span class="n">Install</span><span class="o">]</span>
<span class="n">WantedBy</span><span class="o">=</span><span class="n">multi</span><span class="o">-</span><span class="k">user</span><span class="p">.</span><span class="n">target</span>
<span class="err">$</span><span class="w"> </span><span class="n">sudo</span><span class="w"> </span><span class="n">systemctl</span><span class="w"> </span><span class="n">daemon</span><span class="o">-</span><span class="n">reload</span>
<span class="err">$</span><span class="w"> </span><span class="n">sudo</span><span class="w"> </span><span class="n">systemctl</span><span class="w"> </span><span class="k">start</span><span class="w"> </span><span class="n">kresus</span><span class="p">.</span><span class="n">service</span>
</code></pre></div>
<p>And if everything works fine,</p>
<div class="highlight"><pre><span></span><code>sudo systemctl enable kresus.service
</code></pre></div>
<p>to automatically start your Kresus at every boot.</p>
<h2>Nginx</h2>
<p>Now, we would like our Kresus to be accessible from the rest of our local
network, with an authentication layer on top. We will use Nginx for this, here
is a sample configuration file:</p>
<div class="highlight"><pre><span></span><code><span class="n">server</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nb">listen</span><span class="w"> </span><span class="mi">80</span><span class="w"> </span><span class="n">default_server</span><span class="p">;</span>
<span class="w"> </span><span class="nb">listen</span><span class="w"> </span><span class="p">[</span><span class="o">::</span><span class="p">]:</span><span class="mi">80</span><span class="w"> </span><span class="n">default_server</span><span class="p">;</span>
<span class="w"> </span><span class="n">root</span><span class="w"> </span><span class="sr">/home/</span><span class="n">kresus</span><span class="sr">/kresus/</span><span class="n">build</span><span class="o">/</span><span class="n">client</span><span class="p">;</span>
<span class="w"> </span><span class="c1"># Add index.php to the list if you are using PHP</span>
<span class="w"> </span><span class="nb">index</span><span class="w"> </span><span class="nb">index</span><span class="o">.</span><span class="n">html</span><span class="w"> </span><span class="nb">index</span><span class="o">.</span><span class="n">htm</span><span class="w"> </span><span class="nb">index</span><span class="o">.</span><span class="n">nginx</span><span class="o">-</span><span class="n">debian</span><span class="o">.</span><span class="n">html</span><span class="p">;</span>
<span class="w"> </span><span class="n">server_name</span><span class="w"> </span><span class="n">_</span><span class="p">;</span>
<span class="w"> </span><span class="n">location</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1"># Only proxy the API calls</span>
<span class="w"> </span><span class="n">location</span><span class="w"> </span><span class="o">/</span><span class="n">api</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">proxy_pass</span><span class="w"> </span><span class="n">http:</span><span class="sr">//</span><span class="mf">127.0.0.1</span><span class="p">:</span><span class="mi">9876</span><span class="p">;</span>
<span class="w"> </span><span class="n">proxy_set_header</span><span class="w"> </span><span class="n">Host</span><span class="w"> </span><span class="nv">$host</span><span class="p">;</span>
<span class="w"> </span><span class="n">proxy_set_header</span><span class="w"> </span><span class="n">Proxy</span><span class="w"> </span><span class="s">""</span><span class="p">;</span>
<span class="w"> </span><span class="c1"># Longer timeouts on my (slow) Raspberry Pi</span>
<span class="w"> </span><span class="n">proxy_connect_timeout</span><span class="w"> </span><span class="mi">300</span><span class="p">;</span>
<span class="w"> </span><span class="n">proxy_send_timeout</span><span class="w"> </span><span class="mi">300</span><span class="p">;</span>
<span class="w"> </span><span class="n">proxy_read_timeout</span><span class="w"> </span><span class="mi">300</span><span class="p">;</span>
<span class="w"> </span><span class="n">send_timeout</span><span class="w"> </span><span class="mi">300</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">deny</span><span class="w"> </span><span class="n">all</span><span class="p">;</span>
<span class="w"> </span><span class="n">allow</span><span class="w"> </span><span class="mf">192.168.0.0</span><span class="o">/</span><span class="mi">24</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="c1"># HTTP Authentication</span>
<span class="w"> </span><span class="n">auth_basic</span><span class="w"> </span><span class="s">"Restricted"</span><span class="p">;</span>
<span class="w"> </span><span class="n">auth_basic_user_file</span><span class="w"> </span><span class="sr">/home/</span><span class="n">kresus</span><span class="sr">/kresus/</span><span class="o">.</span><span class="n">htpasswd</span><span class="p">;</span>
<span class="w"> </span><span class="c1"># Security headers</span>
<span class="w"> </span><span class="n">add_header</span><span class="w"> </span><span class="n">x</span><span class="o">-</span><span class="n">xss</span><span class="o">-</span><span class="n">protection</span><span class="w"> </span><span class="s">"1; mode=block"</span><span class="p">;</span>
<span class="w"> </span><span class="n">add_header</span><span class="w"> </span><span class="n">x</span><span class="o">-</span><span class="n">frame</span><span class="o">-</span><span class="n">options</span><span class="w"> </span><span class="s">"DENY"</span><span class="p">;</span>
<span class="w"> </span><span class="n">add_header</span><span class="w"> </span><span class="n">X</span><span class="o">-</span><span class="n">Content</span><span class="o">-</span><span class="n">Type</span><span class="o">-</span><span class="n">Options</span><span class="w"> </span><span class="s">"nosniff"</span><span class="p">;</span>
<span class="w"> </span><span class="n">add_header</span><span class="w"> </span><span class="n">Content</span><span class="o">-</span><span class="n">Security</span><span class="o">-</span><span class="n">Policy</span><span class="w"> </span><span class="s">"default-src 'self'; child-src 'none'; object-src 'none'; img-src 'self' data:;"</span><span class="p">;</span>
<span class="w"> </span><span class="n">add_header</span><span class="w"> </span><span class="n">Referrer</span><span class="o">-</span><span class="n">Policy</span><span class="w"> </span><span class="s">"no-referrer"</span><span class="p">;</span>
<span class="w"> </span><span class="c1"># If using HTTPS, enable the following line</span>
<span class="w"> </span><span class="c1"># add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";</span>
<span class="p">}</span>
</code></pre></div>
<p>It is really important you add <a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-basic-http-authentication-with-nginx-on-ubuntu-14-04"><span class="caps">HTTP</span>
Authentication</a>
on top of it and configure your firewall to limit access to certain IPs (mine
is only accessible from local network). Indeed, out of the box, Kresus does
not provide any form of authentication (to avoid risking to make it wrong).
Then, the <span class="caps">HTTP</span> Authentication layer from your webserver is the <em>only</em>
authentication layer across your install.</p>
<p>As my Raspberry Pi is not web-accessible <a href="http://www.g-rom.info/2017/06/creer-des-certificats-letsencrypt-avec-les-dns-de-ovh/">this alternative <span class="caps">DNS</span>
method</a>
for Let’s Encrypt was useful to get a certificate anyways.</p>
<p>Hope this helps tracking your expenses ! :)</p>
<h2>Bonus part: putting Kresus’ db in <span class="caps">RAM</span></h2>
<p>Kresus is quite slow on a Raspberry Pi v1, even using a good class 10 <span class="caps">SD</span> card
and a bit of overclocking. An easy trick to improve this is to put the
database in <span class="caps">RAM</span>, mounted through <code>tmpfs</code>.</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span><span class="c1"># First, create a mount point</span>
$<span class="w"> </span>mkdir<span class="w"> </span>/home/kresus/kresus_vram<span class="w"> </span><span class="o">&&</span><span class="w"> </span>chown<span class="w"> </span>kresus:kresus<span class="w"> </span>/home/kresus/kresus_vram
$<span class="w"> </span><span class="c1"># Then, mount the tmpfs endpoint</span>
$<span class="w"> </span>cat<span class="w"> </span>/etc/fstab
<span class="o">[</span>…<span class="o">]</span>
tmpfs<span class="w"> </span>/home/kresus/kresus_vram<span class="w"> </span>tmpfs<span class="w"> </span>defaults,size<span class="o">=</span>32M,uid<span class="o">=</span>kresus,gid<span class="o">=</span>kresus<span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="m">0</span>
$<span class="w"> </span><span class="c1"># Set up a crontask to backup to the SD card often (tmpfs is erased after a reboot)</span>
$<span class="w"> </span>sudo<span class="w"> </span>crontab<span class="w"> </span>-u<span class="w"> </span>kresus<span class="w"> </span>-l
*/5<span class="w"> </span>*<span class="w"> </span>*<span class="w"> </span>*<span class="w"> </span>*<span class="w"> </span>/usr/bin/rsync<span class="w"> </span>-ar<span class="w"> </span>/home/kresus/kresus_vram/<span class="w"> </span>/home/kresus/.kresus/
</code></pre></div>
<p>Then, just edit the <code>systemd</code> unit to sync in the other way at startup:</p>
<div class="highlight"><pre><span></span><code>Environment=KRESUS_DIR=/home/kresus/kresus_vram
ExecStartPre=/usr/bin/rsync -ar /home/kresus/.kresus/ /home/kresus/kresus_vram/
</code></pre></div>
<p>And you are all set :)</p>Don du mois de juin : GnuPG2017-07-14T21:34:00+02:002017-07-14T21:34:00+02:00Phykstag:localhost,2017-07-14:/Blog/output/2017/07/don-du-mois-de-juin-gnupg.html<p>Avec beaucoup de retard, déménagement oblige, je continue les <a href="http://localhost/Blog/output/2016/12/don-du-mois-de-decembre-eff.html">dons du
mois</a> en donnant ce mois-ci 10€ à
<a href="https://gnupg.org/cgi-bin/procdonate.cgi?mode=preset&lang=fr">GnuPG</a>.</p>
<p>Pour ceux qui ne connaissent pas, GnuPG est une implémentation libre du
standard OpenPGP qui permet de faire du chiffrement et de la signature de
contenu. J’ai <a href="https://pgp.mit.edu/pks/lookup?op=vindex&search=0xEE367C895DE63E0C">une
clé</a> que …</p><p>Avec beaucoup de retard, déménagement oblige, je continue les <a href="http://localhost/Blog/output/2016/12/don-du-mois-de-decembre-eff.html">dons du
mois</a> en donnant ce mois-ci 10€ à
<a href="https://gnupg.org/cgi-bin/procdonate.cgi?mode=preset&lang=fr">GnuPG</a>.</p>
<p>Pour ceux qui ne connaissent pas, GnuPG est une implémentation libre du
standard OpenPGP qui permet de faire du chiffrement et de la signature de
contenu. J’ai <a href="https://pgp.mit.edu/pks/lookup?op=vindex&search=0xEE367C895DE63E0C">une
clé</a> que
j’utilise pour signer tous mes courriels (et de temps en temps chiffrer des
messages), mais j’utilise surtout quotidiennement GnuPG à travers le
gestionnaire de mots de passe <a href="https://www.passwordstore.org/">pass</a> qui
utilise GnuPG en interne.</p>
<p>Ils ont lancé une <a href="https://gnupg.org/donate/index.html">vaste campagne de
dons</a>, et le don de juin a été fait dans
ce cadre.</p>Don du mois de mai : Regards Citoyens2017-06-07T16:50:00+02:002017-06-07T16:50:00+02:00Phykstag:localhost,2017-06-07:/Blog/output/2017/06/don-du-mois-de-mai-regards-citoyens.html<p>Je continue les <a href="http://localhost/Blog/output/2016/12/don-du-mois-de-decembre-eff.html">dons du mois</a> en donnant
ce mois-ci 12€ à <a href="https://www.regardscitoyens.org">Regards Citoyens</a>, à
travers deux recommandés dans le cadre de leur opération
<a href="http://irfm.regardscitoyens.org/"><span class="caps">IRFM</span></a>.</p>
<p>Regards Citoyens est une association qui cherche à diffuser et partager
l’information politique et publique, à travers la promotion de l’<em>Open Data</em>,
le …</p><p>Je continue les <a href="http://localhost/Blog/output/2016/12/don-du-mois-de-decembre-eff.html">dons du mois</a> en donnant
ce mois-ci 12€ à <a href="https://www.regardscitoyens.org">Regards Citoyens</a>, à
travers deux recommandés dans le cadre de leur opération
<a href="http://irfm.regardscitoyens.org/"><span class="caps">IRFM</span></a>.</p>
<p>Regards Citoyens est une association qui cherche à diffuser et partager
l’information politique et publique, à travers la promotion de l’<em>Open Data</em>,
le <em>lobbying</em> et la diffusion des informations auxquelles ils arrivent à avoir accès.</p>
<p>Ils sont notamment à l’origine d’un certain nombre de projets dont
<a href="https://www.regardscitoyens.org/nosdeputes-fr/">NosDéputés</a> (et sa variante,
<a href="https://www.regardscitoyens.org/nossenateurs-fr/">Nos Sénateurs</a>) pour suivre
l’activité des députés, leur présence en séances et les questions qu’ils
posent, <a href="https://www.regardscitoyens.org/la-fabrique-de-la-loi/">La Fabrique de la
Loi</a> pour suivre
l’évolution de la loi et la <a href="https://www.regardscitoyens.org/interets-des-elus/">numérisation des déclarations d’intérêt des
élus</a>.</p>
<p>Leur dernière opération, <a href="https://irfm.regardscitoyens.org/"><span class="caps">IRFM</span></a> vise à
demander aux députés sortants les justificatifs des dépenses liées à
l’Indemnité Représentatives de Frais de Mandat dont ils bénéficient (5000€
environ, versés tous les mois pour couvrir leurs dépenses liées au mandat).
Pour obtenir ces informations, ils envoient des recommandés avec accusés de
réception à chaque parlementaire, et ont besoin de citoyens pour les aider à
en envoyer. J’ai donc envoyé deux recommandés, à ma députée de mon ancienne
circonscription, où je résidais pendant les dernières élections, et à la
députée de ma circonscription actuelle.</p>
<p>À noter, tous leurs projets sont libres avec <a href="https://www.regardscitoyens.org/publication/#donnees">des dumps téléchargeables</a> et ils publient <a href="https://github.com/regardscitoyens/banque">leur compte en ligne</a>!</p>Mise à jour de mon blog, passage à Pelican2017-06-03T02:05:00+02:002017-06-03T02:05:00+02:00Phykstag:localhost,2017-06-03:/Blog/output/2017/06/mise-a-jour-de-mon-blog-passage-a-pelican.html<p>Je viens de mettre à jour complètement mon blog, en passant de
<a href="https://github.com/idno/Known">Known</a> à
<a href="https://github.com/getpelican/pelican">Pelican</a>. Pelican est un générateur de
sites statiques écrit en Python, avec toutes les fonctionnalités nécessaires
pour écrire un blog.</p>
<p>J’avais commencé avec un système maison équivalent à Pelican, il y a 4 ans
maintenant …</p><p>Je viens de mettre à jour complètement mon blog, en passant de
<a href="https://github.com/idno/Known">Known</a> à
<a href="https://github.com/getpelican/pelican">Pelican</a>. Pelican est un générateur de
sites statiques écrit en Python, avec toutes les fonctionnalités nécessaires
pour écrire un blog.</p>
<p>J’avais commencé avec un système maison équivalent à Pelican, il y a 4 ans
maintenant. Puis j’étais passé à Known, un système dynamique, en <span class="caps">PHP</span>, il y a 2
ans. Je n’ai jamais vraiment utilisé les fonctionnalités proposées par Known,
et en fait je continuais à écrire mes articles dans mon Vim en local, puis à
les publier en utilisant <a href="http://phyks.me/2015/01/publishing-through-the-known-api.html">l’<span class="caps">API</span> qu’offrait
Known</a>, ce qui
n’était pas le plus pratique. Je reviens donc au système initial avec un
moteur de blog purement statique, en me reposant sur Pelican qui est stable et maintenu.</p>
<p>Tous les articles devraient être réimportés dans cette version de mon blog, à
l’exception de mineures modifications d’articles publiés, que j’avais faite
directement en ligne, et qui ont pu être perdues. La plupart des URLs ont dû
êtres conservées également.</p>
<p>Cette migration a été l’occasion de repasser sur tous mes articles, et d’avoir
quelques surprises. J’ai retrouvé <a href="http://phyks.me/2015/01/personal-review-of-the-lenovo-thinkpad-t440.html">mon test du Lenovo
T440</a>,
qui a maintenant plus de deux ans et est toujours mon ordi principal, toujours
au poil, de retrouver des tentatives pour <a href="http://phyks.me/2014/08/synchroniser-ses-ordinateurs-12.html">synchroniser mes
ordis</a> en 2014,
qui n’aboutiront probablement jamais, de relire le <a href="http://phyks.me/2014/03/retour-sur-mon-fairphone.html">test de mon
Fairphone</a> qui a plus
de 3 ans maintenant, et que j’utilise toujours quotidiennement (et qui
fonctionne toujours très bien, même si je suis probablement moins exigeant
qu’à l’époque), et enfin de revoir tout un tas d’astuces et de configurations
que j’utilise toujours (à commencer par <a href="http://phyks.me/2014/02/local-notifications-for-weechat-and-urxvt.html">les notifications locales dans
Weechat</a>).</p>
<p>L’ancien lien du flux <span class="caps">RSS</span> devrait toujours fonctionner, mais je vous invite à
utiliser dès à présent <a href="http://phyks.me/feeds/all.atom.xml">le nouveau lien</a>
afin d’éviter tout problème.</p>Don du mois d’avril : Nos Oignons2017-05-03T19:45:00+02:002017-05-03T19:45:00+02:00Phykstag:localhost,2017-05-03:/Blog/output/2017/05/don-du-mois-davril-nos-oignons.html<p>Je continue les <a href="http://localhost/Blog/output/2016/12/don-du-mois-de-decembre-eff.html">dons du mois</a> en donnant
ce mois-ci 14€ (+1€ de comission pour HelloAsso) à <a href="https://nos-oignons.net/">Nos
Oignons</a>, ce qui couvre un peu plus d’une journée de
fonctionnement selon leur site.</p>
<p>Nos Oignons est une association dont le but est de collecter des dons afin de
faire tourner …</p><p>Je continue les <a href="http://localhost/Blog/output/2016/12/don-du-mois-de-decembre-eff.html">dons du mois</a> en donnant
ce mois-ci 14€ (+1€ de comission pour HelloAsso) à <a href="https://nos-oignons.net/">Nos
Oignons</a>, ce qui couvre un peu plus d’une journée de
fonctionnement selon leur site.</p>
<p>Nos Oignons est une association dont le but est de collecter des dons afin de
faire tourner des nœuds de sortie Tor. Ainsi, ils contribuent des nœuds Tor de
qualité, avec une bande passante et des performances confortables. Cela permet
aussi de diversifier la source des nœuds Tor, car il faut éviter qu’un même
organisme contrôle une part significative des relais Tor.</p>
<p>Ils expliquent tout ça (et plus) bien mieux que ce que je pourrais faire dans
un court message <a href="https://nos-oignons.net/%C3%80_propos/index.fr.html">sur leur
site</a>.</p>Filtering ads with your Raspberry Pi2017-04-04T19:16:00+02:002017-04-04T19:16:00+02:00Phykstag:localhost,2017-04-04:/Blog/output/2017/04/filtering-ads-with-your-raspberry-pi.html<p><span class="caps">TL</span>;<span class="caps">DR</span>: Please have a look at the benchmark section below, to be aware of the
limitations of this particular setup and decide whether to spend some time
putting it in place or not.</p>
<p>I recently came across <a href="https://github.com/pi-hole/pi-hole">this Pi-Hole
project</a> that claims to be “a black hole
for Internet …</p><p><span class="caps">TL</span>;<span class="caps">DR</span>: Please have a look at the benchmark section below, to be aware of the
limitations of this particular setup and decide whether to spend some time
putting it in place or not.</p>
<p>I recently came across <a href="https://github.com/pi-hole/pi-hole">this Pi-Hole
project</a> that claims to be “a black hole
for Internet advertisements” (thanks <a href="https://nicofrand.eu/">nicofrand</a> for
making me discover this!). The idea was really attractive: having a simple
Raspberry Pi on the network doing all the ad filtering for the whole network,
rather than having to maintain a separate <a href="https://github.com/gorhill/uBlock">uBlock
Origin</a> install on each and every computers
of the network. It was also particularly attractive as having such ad blocker
on a smartphone requires a rooted device. Plus there was a really nice web
interface to control the whole ad blocking device.</p>
<p>While looking at it more in depth, I realized it was actually very limited:</p>
<ol>
<li>First, it was built around specific softwares and was doing some magical
stuff using these softwares. It was really painful to get away from them.
Basically, it uses <code>dnsmasq</code> to expose a <span class="caps">DNS</span> service, a standard <code>hosts</code>
file to block the hosts serving ads, and a lighthttpd webserver. Problem is
I already have a <span class="caps">DNS</span> resolver (<code>unbound</code>) on this Raspberry Pi, and a web
server (<code>nginx</code>). I did not want to spend a lot of time trying to integrate
it in my existing setup if finally it was not that powerful, so I decided
to look at it in details before installing.</li>
<li>Second issue was that it relies on <code>dnsmasq</code>. <code>dnsmasq</code> is a simple program
that allow you to answer <span class="caps">DNS</span> queries by using the hosts defined in
<code>/etc/hosts</code> and to forward every other requests to another <span class="caps">DNS</span> server
(typically your <span class="caps">ISP</span> <span class="caps">DNS</span> server). Pi-Hole lets you configure two <span class="caps">DNS</span> servers
to forward queries to, default one being 8.8.8.8 (<code>Google</code> :/). I already
have a resolver on this Raspberry-Pi and I do want to do the resolution
myself, especially since my <span class="caps">ISP</span> <span class="caps">DNS</span> servers lies, and I do not want to use
public <span class="caps">DNS</span> server on another network. So I had to hack on Pi-Hole to do
some <span class="caps">DNS</span> resolution. About these issues, I’d like to point to two very
interesting articles from <a href="http://www.bortzmeyer.org/">Bortzmeyer</a>: <a href="http://www.bortzmeyer.org/google-dns">this
one about Google <span class="caps">DNS</span></a> (in French) and
<a href="http://www.bortzmeyer.org/son-propre-resolveur-dns.html">this one about having your own <span class="caps">DNS</span>
resolver</a> (same).
Also, being a <span class="caps">DNS</span> resolver, it may be cumbersome to disable it temporarily
to load some website that absolutely requires the ads to be loaded.</li>
<li>Last issue was that contrary to uBlock which filters at the requests level
(and even sometimes at the <span class="caps">HTML</span> level), the fact that is basically an
alternative <span class="caps">DNS</span> resolver means you can only filter at the domain level.
That is, you either whitelist (default) or blacklist a domain which is
serving ads or malwares, but you cannot differentiate different paths for a
given domain. While browsing <a href="http://liberation.fr/">Libération website</a>, I
can see uBlock is blocking queries such as
<code>http://s3.amazonaws.com/files.wrapper.theadtech.com/native/placements/liberation.fr/pconfig?r=5a6f5d98b4d608</code>.
Such queries <strong>cannot</strong> be blocked by Pi-Hole without blacklisting the
whole Amazon S3 network.</li>
</ol>
<p>Given these facts, I remembered <a href="https://www.privoxy.org/">Privoxy</a> which can
be used as a filtering proxy, in a way similar to uBlock. Given that it is a
proxy, it can filter in details, just as uBlock do and you can very easily
disable it (simply disable the proxy). Plus, almost any devices offer you a
proxy setting, so it should work both on my Android phones and computers. In
this article I describe how I set up a Pi-Hole alternative based on Unbound
(to have my own <span class="caps">DNS</span> resolver and block some things at the domain level)
coupled with a Privoxy proxy to filter out ads.</p>
<p><strong>Limitations</strong>: So, contrary to Pi-Hole, the setup described here will be
able to remove ads in a similar way to uBlock/AdBlock. If you go through the
whole article till the end, it will also have the element hiding features.
Being a proxy setting, it will be easy to toggle it on and off (either by
Prixovy toggling features or by manually turning off proxy on your device), if
required. However, be aware of the remaining limitations with regards to <span class="caps">HTTPS</span>
streams (<a href="https://www.privoxy.org/faq/misc.html">section 4.15</a>). As
AdBlock/uBlock runs in the browser, it can filter ads in <span class="caps">HTTPS</span> streams as
well, Privoxy will not be as efficient without <span class="caps">HTTPS</span> interception (which is
generally not a good idea). However, it should perform rather well in the vast
majority of situations (also note that AdBlock for rooted Android devices is
also a proxy, so for them, it will not change anything).</p>
<p>I assume you already have a running Raspberry Pi with some basic install.
Typically, see <a href="http://localhost/Blog/output/2017/02/raspberry-pi-install-checklist.html">this previous
article</a> if this is not
the case</p>
<h2>Set up a <span class="caps">DNS</span> resolver</h2>
<p>Let’s install a <span class="caps">DNS</span> resolver on the Raspberry Pi, to answer <span class="caps">DNS</span> queries on the
network. I am installing unbound and configuring Unbound here.</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>unbound
<span class="gp">$ </span>curl<span class="w"> </span>-o<span class="w"> </span>/etc/unbound/root.hints<span class="w"> </span>https://www.internic.net/domain/named.cache
<span class="gp">$ </span><span class="c1"># (Optional) Set crontask to download root.hints file every six months</span>
</code></pre></div>
<p>The last <code>curl</code> command is used to fetch the root hints, to query hosts that
are not cached. See <a href="https://wiki.archlinux.org/index.php/unbound#Root_hints">this section of the ArchWiki
page</a> for more infos.</p>
<p>Then, you can create a basic configuration file for unbound.</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>cat<span class="w"> </span>/etc/unbound/unbound.conf.d/local.conf
<span class="go">server:</span>
<span class="go"> username: "unbound"</span>
<span class="go"> interface: 0.0.0.0 # Listen on all interfaces</span>
<span class="go"> root-hints: "/etc/unbound/root.hints"</span>
<span class="go"> access-control: 192.168.0.0/8 allow # Access-control, see "Example" section in https://www.unbound.net/documentation/unbound.conf.html</span>
</code></pre></div>
<p>Then, enable and start Unbound service at startup:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>sudo<span class="w"> </span>systemctl<span class="w"> </span>start<span class="w"> </span>unbound<span class="w"> </span><span class="o">&&</span><span class="w"> </span>sudo<span class="w"> </span>systemctl<span class="w"> </span><span class="nb">enable</span><span class="w"> </span>unbound
</code></pre></div>
<p>You can now change the resolver to be used on your Raspberry Pi and on your
whole network. To change it on your Raspberry Pi, have a look at <a href="https://wiki.debian.org/NetworkConfiguration#Defining_the_.28DNS.29_Nameservers">this wiki
page</a>
(for Raspbian). To set it as the default <span class="caps">DNS</span> resolver on your network, have a
look at your router configuration, and set the <span class="caps">DNS</span> resolvers address to the
address of your Raspberry Pi. Don’t forget to open the ports in your firewall
(53 tcp and udp).</p>
<p>To check everything is working fine, you can use <code>dig</code> (from <code>dnsutils</code>
package on Debian-based distributions). Typically, <code>dig google.fr</code> should give
you some results (in the <code>ANSWER SECTION</code>) and the <span class="caps">IP</span> address in the <code>SERVER</code>
line should be the one of your Raspberry Pi.</p>
<p><strong>Note</strong>: At this point, we should emphasize that having an open <span class="caps">DNS</span> resolver
(that is, a <span class="caps">DNS</span> resolver that can answer to anyone) can be a security risk
especially since <a href="https://www.incapsula.com/ddos/attack-glossary/dns-amplification.html">some DDoS attacks use
it</a>.
Then, you should make sure that your Raspberry Pi <span class="caps">DNS</span> server is only
accessible from your local network, and that no third-party has access to it.
This should be done through the <code>access-control</code> line in the above
configuration, but this can also be enforced by the firewall running on your
Raspberry Pi and the firewall on your router (typically, most routers provided
by your <span class="caps">ISP</span> block any incoming connections, check this).</p>
<h2>Block some domains based on hosts</h2>
<p>Now, we would like <code>unbound</code> to block some domains that are known to serve ads
and malwares, in a similar way as Pi-Hole does. For this purpose, we will use
<a href="https://github.com/jodrell/unbound-block-hosts"><code>unbound-block-hosts</code></a> script
to import <code>hosts</code> files into Unbound configuration. Basically, for every such
domain, Unbound will return <code>127.0.0.1</code>.</p>
<p><code>unbound-block-hosts</code> is designed with the <a href="http://someonewhocares.org/">Dan Pollock’s hosts
file</a> in mind, whereas I wanted to be able to
import any host file in Unbound.
<a href="https://github.com/Phyks/unbound-block-hosts">Here</a> is a forked and patched
version for this purpose (very ugly patch, as I am not fluent in Perl :/).</p>
<p>We will create an <code>includes</code> dir in the Unbound configuration directory
(<code>mkdir /etc/unbound/includes/</code>), and include the rules in the main
configuration by appending <code>include: "/etc/unbound/includes/*.conf"</code> to the
<code>/etc/unbound/unbound.conf.d/local.conf</code> previously created.</p>
<p>Now, you can run <code>./unbound-block-hosts --url="SOME_URL"
--file=/etc/unbound/includes/FOOBAR-blocking.conf</code> to generate a matching
configuration for a given <code>hosts</code> list. Typically, I have a script doing:</p>
<div class="highlight"><pre><span></span><code><span class="c1">#/bin/sh</span>
<span class="nb">set</span><span class="w"> </span>-e
<span class="nb">cd</span><span class="w"> </span><span class="s2">"</span><span class="k">$(</span>dirname<span class="w"> </span><span class="s2">"</span><span class="nv">$0</span><span class="s2">"</span><span class="k">)</span><span class="s2">"</span>
<span class="nb">echo</span><span class="w"> </span><span class="s2">"Fetch Malware domains list and append to unbound"</span>
./unbound-block-hosts<span class="w"> </span>--url<span class="o">=</span><span class="s2">"http://www.malwaredomainlist.com/hostslist/hosts.txt"</span><span class="w"> </span>--file<span class="o">=</span>/etc/unbound/includes/malwaredomainlist-blocking.conf<span class="w"> </span>--address<span class="o">=</span><span class="s2">"YOUR_RASPBERRY_PI_IP"</span>
<span class="nb">echo</span><span class="w"> </span><span class="s2">"Fetch Yoyo ad servers list and append to unbound"</span>
curl<span class="w"> </span><span class="s2">"https://pgl.yoyo.org/adservers/serverlist.php?hostformat=unbound;showintro=0&mimetype=plaintext"</span><span class="w"> </span>><span class="w"> </span>/etc/unbound/includes/yoyoadservers-blocking.conf
systemctl<span class="w"> </span>reload<span class="w"> </span>unbound
</code></pre></div>
<p>which is crontask-ed to run every day. Default address is <code>127.0.0.1</code> which
means the local host for the client machine. I do not want to have too many
404 on my local webservers, so I’d rather put the <span class="caps">IP</span> address of the Raspberry
Pi and have a webserver answering a 404 on it.</p>
<h2>Install a webserver</h2>
<p>As simple as</p>
<div class="highlight"><pre><span></span><code>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>nginx
</code></pre></div>
<h2>Install and configure Privoxy</h2>
<p>Now, you can install Privoxy:</p>
<div class="highlight"><pre><span></span><code>sudo<span class="w"> </span>apt-get<span class="w"> </span>install<span class="w"> </span>privoxy
</code></pre></div>
<p>The default configuration should be mostly ok. You can look at the
<code>/etc/privoxy/config</code> file to adapt it to your needs (the file is really an
example of well documented config file). Two options you might be interesting
in changing are the <code>debug</code> option (to enable logging, which is disabled by
default) and <code>listen-addr</code>. You will want to set the latter to:</p>
<div class="highlight"><pre><span></span><code>listen-address 127.0.0.1:8118
listen-address YOUR_RASPBERRY_PI_IP:8118
</code></pre></div>
<p>so that the Prixovy proxy is accessible from the rest of your <span class="caps">LAN</span>. As always,
do not forget to configure your firewall to let the Privoxy connections pass
through. At this point, you should try to set the proxy in your browser’s
preferences and check that everything is working fine. You should be able to
browse to any web page, but the proxy will not do anything else for the moment.</p>
<p><strong>Note</strong>: At this point, we should emphasize that having such a proxy is a
security risk, as anyone having access to your proxy can browse the web with
your <span class="caps">IP</span> address (and you may be held liable for anything illegal done with
it). Then, you should make sure that your Raspberry Pi Privoxy is only
accessible from your local network, and that no third-party has access to it.
This should be enforced by the firewall running on your Raspberry Pi and the
firewall on your router (typically, most routers provided by your <span class="caps">ISP</span> block
any incoming connections, check this).</p>
<p>Privoxy, as installed by the Raspbian package, enables a couple of filters out
of the box. As we will be translating Adblock rules into Privoxy rules, we can
disable them. Edit the <code>/etc/privoxy/match-all.action</code> file to get something
like this:</p>
<div class="highlight"><pre><span></span><code>#############################################################################
#<span class="w"> </span><span class="nv">Id</span>:<span class="w"> </span><span class="nv">match</span><span class="o">-</span><span class="nv">all</span>.<span class="nv">action</span>,<span class="nv">v</span>
#
#<span class="w"> </span><span class="nv">This</span><span class="w"> </span><span class="nv">file</span><span class="w"> </span><span class="nv">contains</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">actions</span><span class="w"> </span><span class="nv">that</span><span class="w"> </span><span class="nv">are</span><span class="w"> </span><span class="nv">applied</span><span class="w"> </span><span class="nv">to</span><span class="w"> </span><span class="nv">all</span><span class="w"> </span><span class="nv">requests</span><span class="w"> </span><span class="nv">and</span>
#<span class="w"> </span><span class="nv">may</span><span class="w"> </span><span class="nv">be</span><span class="w"> </span><span class="nv">overruled</span><span class="w"> </span><span class="nv">later</span><span class="w"> </span><span class="nv">on</span><span class="w"> </span><span class="nv">by</span><span class="w"> </span><span class="nv">other</span><span class="w"> </span><span class="nv">actions</span><span class="w"> </span><span class="nv">files</span>.<span class="w"> </span><span class="nv">Less</span><span class="w"> </span><span class="nv">experienced</span>
#<span class="w"> </span><span class="nv">users</span><span class="w"> </span><span class="nv">should</span><span class="w"> </span><span class="nv">only</span><span class="w"> </span><span class="nv">edit</span><span class="w"> </span><span class="nv">this</span><span class="w"> </span><span class="nv">file</span><span class="w"> </span><span class="nv">through</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">actions</span><span class="w"> </span><span class="nv">file</span><span class="w"> </span><span class="nv">editor</span>.
#
#############################################################################
{<span class="w"> </span>\
<span class="o">+</span><span class="nv">change</span><span class="o">-</span><span class="nv">x</span><span class="o">-</span><span class="nv">forwarded</span><span class="o">-</span><span class="k">for</span>{<span class="nv">block</span>}<span class="w"> </span>\
<span class="o">+</span><span class="nv">client</span><span class="o">-</span><span class="nv">header</span><span class="o">-</span><span class="nv">tagger</span>{<span class="nv">css</span><span class="o">-</span><span class="nv">requests</span>}<span class="w"> </span>\
<span class="o">+</span><span class="nv">client</span><span class="o">-</span><span class="nv">header</span><span class="o">-</span><span class="nv">tagger</span>{<span class="nv">image</span><span class="o">-</span><span class="nv">requests</span>}<span class="w"> </span>\
<span class="o">+</span><span class="nv">filter</span>{<span class="nv">refresh</span><span class="o">-</span><span class="nv">tags</span>}<span class="w"> </span>\
<span class="o">+</span><span class="nv">filter</span>{<span class="nv">webbugs</span>}<span class="w"> </span>\
<span class="o">+</span><span class="nv">filter</span>{<span class="nv">jumping</span><span class="o">-</span><span class="nv">windows</span>}<span class="w"> </span>\
<span class="o">+</span><span class="nv">filter</span>{<span class="nv">ie</span><span class="o">-</span><span class="nv">exploits</span>}<span class="w"> </span>\
<span class="o">+</span><span class="nv">hide</span><span class="o">-</span><span class="nv">from</span><span class="o">-</span><span class="nv">header</span>{<span class="nv">block</span>}<span class="w"> </span>\
<span class="o">+</span><span class="nv">hide</span><span class="o">-</span><span class="nv">referrer</span>{<span class="nv">conditional</span><span class="o">-</span><span class="nv">block</span>}<span class="w"> </span>\
}
<span class="o">/</span><span class="w"> </span>#<span class="w"> </span><span class="nv">Match</span><span class="w"> </span><span class="nv">all</span><span class="w"> </span><span class="nv">URLs</span>
</code></pre></div>
<p>In particular, I disabled the filters <code>img-reorder</code> (which is really intensive
for the Raspberry Pi, and takes a few hundreds of milliseconds to process a
regular page) and <code>banners-by-size</code> as we will be importing Adblock rules
which should give better results. <code>deanimate-gifs</code> and <code>session-cookies-only</code>
is a matter of taste (respectively it prevents animated GIFs by replacing them
by their last frame and only allowing temporary cookies).</p>
<h2>Block ads using Privoxy</h2>
<p>We will now be importing adBlock rules into privoxy. One way to do it is to
use <a href="http://projects.zubr.me/wiki/adblock2privoxy">this Haskell script</a>.</p>
<p>To install it directly on your Raspberry Pi, provided you have a recent
Raspberry Pi:</p>
<ul>
<li>Install Haskell Stack http://allocinit.io/haskell/haskell-on-raspberry-pi-3/
(if you are feeling adventurous)</li>
<li>Install adblock2privoxy https://projects.zubr.me/wiki/adblock2privoxy#from-sources</li>
</ul>
<p>This was not my case, so I set up a builder on my server to run daily. Some
rules are <a href="http://projects.zubr.me/wiki/adblock2privoxyDownloads">provided by the
author</a> and my builds
are available <a href="http://pub.phyks.me/adblock2privoxy">here</a>.</p>
<p>The way to set up the resulting files into Privoxy is very well detailed on
<a href="http://projects.zubr.me/wiki/adblock2privoxy#how-to-apply-results">the page of the
project</a>.</p>
<p><em>Note</em>: My builds are made with the Element Hiding feature and <code>example.com</code>
as the <code>domainCSS</code> parameter. You should replace any occurrence of
<code>example.com</code> by the <span class="caps">FQDN</span> or <span class="caps">IP</span> adrdess of your Raspberry Pi when importing
it. Please, do not put too much load on my hosted builds and consider hosting
your owns.</p>
<h2>Benchmark</h2>
<p>All the tests were made with a Raspberry Pi of the first model with <span class="caps">512MB</span> of
<span class="caps">RAM</span> (model 1B). The Raspberry Pi has a wired access to internet (<span class="caps">100MB</span>/s port
only on the Raspberry Pi). My laptop is wired as well (gigabit ethernet). Home
connection to internet is a fiber access (923 Mbps download, 250 Mbps upload,
as reported by
<a href="https://www.dslreports.com/speedtest?httpsok=1&r=489">DSLReports</a>).</p>
<h3>Testing the <span class="caps">DNS</span> server</h3>
<p>Without the <span class="caps">DNS</span> server,</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span><span class="c1"># Using my ISP resolver</span>
<span class="gp">$ </span>%<span class="w"> </span>dig<span class="w"> </span>@192.168.0.254<span class="w"> </span>example.com
<span class="go">...</span>
<span class="go">;; Query time: 7 msec</span>
<span class="go">;; SERVER: 192.168.0.254#53(192.168.0.254)</span>
<span class="gp">$ </span><span class="c1"># Using Google DNS</span>
<span class="gp">$ </span>dig<span class="w"> </span>@8.8.8.8<span class="w"> </span>example.com
<span class="go">...</span>
<span class="go">;; Query time: 5 msec</span>
<span class="go">;; SERVER: 8.8.8.8#53(8.8.8.8)</span>
<span class="gp">$ </span><span class="c1"># Using the DNS resolver on my Raspberry Pi</span>
<span class="gp">$ </span>dig<span class="w"> </span>@192.168.0.1<span class="w"> </span>example.com
<span class="go">...</span>
<span class="go">;; Query time: 505 msec</span>
<span class="go">;; SERVER: 192.168.0.1#53(192.168.0.1)</span>
<span class="gp">$ </span><span class="c1"># Using it another time, now that the domain is in cache</span>
<span class="gp">$ </span>dig<span class="w"> </span>@192.168.0.1<span class="w"> </span>example.com
<span class="go">...</span>
<span class="go">;; Query time: 5 msec</span>
<span class="go">;; SERVER: 192.168.0.1#53(192.168.0.1)</span>
</code></pre></div>
<p>These are typical times, the value is typically the one obtained as average
of a few runs.</p>
<p>We can see that there is some overhead when first accessing a domain, as the
Pi has to do the full <span class="caps">DNS</span> resolution. Afterwards, the domain is kept in cache
and it is as fast to use the <span class="caps">DNS</span> server from the Pi as it is to use any other one.</p>
<h3>Testing the Privoxy setup</h3>
<p>Now, let us focus on the performances of the Privoxy on the Raspberry Pi. I
tested it with a few websites, and results were roughly the same. Here is a
detailed example of <a href="http://www.liberation.fr/direct/">Liberation’s website</a>,
a French journal. This example is interesting as my µBlock setup on my laptop
blocks 23 different things when I don’t use the <span class="caps">DNS</span> nor the Privoxy proxy. It
is also an interesting example as out of the 23 blocked contents, only 14 of
them could be blocked by <span class="caps">DNS</span> (with the setup described above).</p>
<p>The main issue here is that Privoxy is very long to process the page with all
the filters, and it is way too heavy for my low power Raspberry Pi first model.</p>
<p>The main <span class="caps">HTML</span> document for this page takes 7 seconds to load when passing
through the proxy, mainly due to the processing time. When reloading the page,
it only takes 400ms as it is already in cache. As a comparison, it takes only
24ms when loading it directly.</p>
<p>The complete setup looks equivalent to the µBlock setup on my laptop.</p>
<p>I don’t have a more recent version of the Raspberry Pi (typically Raspberry Pi
3) to test what the performances are on such a more powerful system. If you
can try it, let me know, I am curious about the way it handles the load, and I
could publish an edit to this article.</p>
<p><strong><span class="caps">EDIT</span></strong>: A related article of interest is
<a href="https://www.shaftinc.fr/blocage-pubs-unbound.html">https://www.shaftinc.fr/blocage-pubs-unbound.html</a>.</p>Don du mois de mars : Jupyter2017-03-31T19:58:00+02:002017-03-31T19:58:00+02:00Phykstag:localhost,2017-03-31:/Blog/output/2017/03/don-du-mois-de-mars-jupyter.html<p>Je continue les <a href="http://localhost/Blog/output/2016/12/don-du-mois-de-decembre-eff.html">dons du mois</a> en donnant
ce mois-ci 15€ à <a href="https://jupyter.org/">Jupyter</a>.</p>
<p>Jupyter (anciennement iPython) est issu de <a href="https://linuxfr.org/news/ipython-est-mort-vive-ipython-4-0">la
scission</a> entre
iPython (le noyau) et la partie <em>notebook</em> (feuilles de calcul). Jupyter
Notebook recouvre cette deuxième partie, et supporte différents noyaux en plus
de Python (R, Haskell, Julia, Ruby …</p><p>Je continue les <a href="http://localhost/Blog/output/2016/12/don-du-mois-de-decembre-eff.html">dons du mois</a> en donnant
ce mois-ci 15€ à <a href="https://jupyter.org/">Jupyter</a>.</p>
<p>Jupyter (anciennement iPython) est issu de <a href="https://linuxfr.org/news/ipython-est-mort-vive-ipython-4-0">la
scission</a> entre
iPython (le noyau) et la partie <em>notebook</em> (feuilles de calcul). Jupyter
Notebook recouvre cette deuxième partie, et supporte différents noyaux en plus
de Python (R, Haskell, Julia, Ruby, etc). Un bon exemple du rendu est
disponible <a href="https://nbviewer.jupyter.org/github/ipython/ipython/blob/4.0.x/examples/IPython%20Kernel/Trapezoid%20Rule.ipynb">ici</a> (en lecture seule).</p>
<p>Une feuille de calculs est composée de cellules, et chaque cellule peut être
soit du texte (markdown étendu avec le support de LaTeX pour les équations,
rendues avec MathJaX), soit du code. C’est un très bon outil pour faire un
genre de <a href="https://fr.wikipedia.org/wiki/Programmation_lettr%C3%A9e">programmation
lettrée</a> où code et
équations sont ensemble, dans un unique document cohérent. De plus, Jupyter
supporte l’export vers de nombreux formats (grâce à LaTeX et à Pandoc), et
notamment <span class="caps">PDF</span>, TeX et <span class="caps">HTML</span>, ce qui permet de générer un document final propre
contenant l’intégralité des notes et des simulations pour un projet donné.</p>Don du mois de février : i3wm2017-03-31T19:45:00+02:002017-03-31T19:45:00+02:00Phykstag:localhost,2017-03-31:/Blog/output/2017/03/don-du-mois-de-fevrier-i3wm.html<p>J’ai été assez débordé le mois dernier et viens de me rendre compte que mon
article sur le don du mois de février était resté en brouillon non publié :/</p>
<p>Je continue donc les <a href="http://localhost/Blog/output/2016/12/don-du-mois-de-decembre-eff.html">dons du mois</a> en
donnant ce mois-ci 15€ à <a href="http://i3wm.org/">i3wm</a>.</p>
<p>i3wm est un gestionnaire de fenêtres …</p><p>J’ai été assez débordé le mois dernier et viens de me rendre compte que mon
article sur le don du mois de février était resté en brouillon non publié :/</p>
<p>Je continue donc les <a href="http://localhost/Blog/output/2016/12/don-du-mois-de-decembre-eff.html">dons du mois</a> en
donnant ce mois-ci 15€ à <a href="http://i3wm.org/">i3wm</a>.</p>
<p>i3wm est un gestionnaire de fenêtres pour X11 (Linux) qui fait du <em>tiling</em>
(“pavage” en bon français). Il organise automatiquement les fenêtres à
l’écran, de sorte qu’elles ne se superposent jamais, mais pavent l’espace disponible.</p>
<p>Je l’utilise quotidiennement, et une fois qu’on l’a testé (et qu’on s’y est
habitué), ça devient très rapidement indispensable.</p>
<p>À noter, il existe une alternative (sans lien avec i3wm) pour Wayland :
<a href="https://github.com/SirCmpwn/sway">sway</a>.</p>Raspberry Pi install checklist2017-02-28T19:45:00+01:002017-02-28T19:45:00+01:00Phykstag:localhost,2017-02-28:/Blog/output/2017/02/raspberry-pi-install-checklist.html<p><strong><span class="caps">UPDATE</span></strong> (13/07/2017): Removed RPi-Monitor and replaced it by
<a href="http://www.monitorix.org/">Monitorix</a>.</p>
<p>This is some memo for me, to use as a checklist whenever I set up a new
Raspberry Pi which is to be running continuously (typically as a webserver).</p>
<p>First, I start from the <a href="https://downloads.raspberrypi.org/raspbian_lite_latest">lite
version</a> of Raspbian.</p>
<p>After …</p><p><strong><span class="caps">UPDATE</span></strong> (13/07/2017): Removed RPi-Monitor and replaced it by
<a href="http://www.monitorix.org/">Monitorix</a>.</p>
<p>This is some memo for me, to use as a checklist whenever I set up a new
Raspberry Pi which is to be running continuously (typically as a webserver).</p>
<p>First, I start from the <a href="https://downloads.raspberrypi.org/raspbian_lite_latest">lite
version</a> of Raspbian.</p>
<p>After install:</p>
<ol>
<li>
<p><code>sudo apt-get update && sudo apt-get upgrade</code></p>
</li>
<li>
<p><code>sudo raspi-config</code> and tweak according to my needs.</p>
</li>
<li>
<p>Install some useful tools:</p>
</li>
</ol>
<div class="highlight"><pre>
sudo apt-get install ack-grep fail2ban git heirloom-mailx htop libxml2-dev libxslt1-dev libyaml-dev moreutils msmtp-mta python-dev python-pip python3 python3-dev python3-pip screen vim zlib1g-dev
</pre></div>
<ol>
<li>Install <code>Monitorix</code>:</li>
</ol>
<div class="highlight"><pre>
\# Install dependencies
$ sudo apt-get install rrdtool perl libwww-perl libmailtools-perl libmime-lite-perl librrds-perl \
libdbi-perl libxml-simple-perl libhttp-server-simple-perl libconfig-general-perl \
libio-socket-ssl-perl
\# Install nginx and fcgiwrap
$ sudo apt-get install nginx fcgiwrap
</pre></div>
<p>Then, download the latest Monitorix Debian package <a href="http://www.monitorix.org/downloads.html">from here</a>.</p>
<div class="highlight"><pre>
\# Install the package
$ dpkg -i monitorix_3.9.0-izzy1_all.deb
</pre></div>
<p>Then, configure it in <code>/etc/monitorix/monitorix.conf</code> and enable graphs you
want (<code>graph_enable</code>).</p>
<ol>
<li>
<p>Some useful bash config: <code>echo 'export PATH=$HOME/.local/bin:$PATH' >> $HOME/.bashrc; echo 'export EDITOR=vim' >> $HOME/.bashrc</code>.</p>
</li>
<li>
<p>Use <span class="caps">NTP</span> to keep the system in sync with current time: <code>sudo timedatectl set-ntp true</code>.</p>
</li>
<li>
<p>Load <code>ip_conntrack_ftp</code> module: <code>sudo echo "ip_conntrack_ftp" >> /etc/modules-load.d/modules.conf</code>.</p>
</li>
<li>
<p>Set up an <code>iptables</code> systemd service <em>à la</em> Arch Linux. See <a href="https://github.com/srdja/debian-systemd-iptables/tree/master/systemd-iptables1.1-0/usr/lib/systemd/system">this
unit</a>. Put <code>iptables</code> config in <code>/etc/iptables/ip{6,}tables.rules</code>.</p>
</li>
<li>
<p>Remove the file in <code>/etc/sudoers.d</code> which prevents <code>pi</code> user from having
to type its password.</p>
</li>
<li>
<p>Configure <code>msmtp</code> to be able to send emails using the mailserver on my
main server.</p>
</li>
<li>
<p>Harden <span class="caps">SSH</span> configuration as you would do for a server.</p>
</li>
<li>
<p><code>sudo rm /etc/profile.d/sshpasswd.sh</code> to remove a useless profile script
raising security alerts when connecting through <span class="caps">SSH</span> with a not
passwordless <code>sudo</code> user.</p>
</li>
<li>
<p>Set a <code>MAILTO</code> address in <code>crontab</code> and edit <code>aliases</code>.</p>
</li>
</ol>Don du mois de janvier : Framasoft2017-01-31T19:45:00+01:002017-01-31T19:45:00+01:00Phykstag:localhost,2017-01-31:/Blog/output/2017/01/don-du-mois-de-janvier-framasoft.html<p>Je continue les <a href="http://localhost/Blog/output/2016/12/don-du-mois-de-decembre-eff.html">dons du mois</a> en donnant
ce mois-ci 15€ à <a href="http://framasoft.org/">Framasoft</a>.</p>
<p>Framasoft est un réseau dédié à la promotion du « libre » en général et du
logiciel libre en particulier et offre de nombreux services et projets
innovants mis librement à disposition du grand public, notamment dans le cadre …</p><p>Je continue les <a href="http://localhost/Blog/output/2016/12/don-du-mois-de-decembre-eff.html">dons du mois</a> en donnant
ce mois-ci 15€ à <a href="http://framasoft.org/">Framasoft</a>.</p>
<p>Framasoft est un réseau dédié à la promotion du « libre » en général et du
logiciel libre en particulier et offre de nombreux services et projets
innovants mis librement à disposition du grand public, notamment dans le cadre
de leur campagne de <a href="https://degooglisons-internet.org">« dégooglisation
»</a> (des services libres, hébergés par
Framasoft, qui offrent des alternatives aux services offerts par Google /
Doodle / Facebook / Github etc, et la liste va croissante !). Bien évidemment,
les services peuvent être très facilement autohébergés, et ils l’encouragent à
travers leur campagne des <a href="https://chatons.org/"><span class="caps">CHATONS</span></a>.</p>
<p>En particulier, leur <a href="https://degooglisons-internet.org/alternatives">liste
d’alternatives</a> est très bien
faite et très pertinente.</p>Don du mois de décembre : EFF2016-12-21T15:46:00+01:002016-12-21T15:46:00+01:00Phykstag:localhost,2016-12-21:/Blog/output/2016/12/don-du-mois-de-decembre-eff.html<p>Je suis tombé sur les <a href="http://sametmax.com/le-don-du-mois-mozilla/">dons du
mois</a> de Sam <span class="amp">&</span> Max, qui donnaient
chaque mois à une organisation qui fournit des produits et des services qu’ils
utilisaient et qui avaient été importants pour eux le mois passé, tout en
écrivant un billet sur leur blog afin de faire parler …</p><p>Je suis tombé sur les <a href="http://sametmax.com/le-don-du-mois-mozilla/">dons du
mois</a> de Sam <span class="amp">&</span> Max, qui donnaient
chaque mois à une organisation qui fournit des produits et des services qu’ils
utilisaient et qui avaient été importants pour eux le mois passé, tout en
écrivant un billet sur leur blog afin de faire parler de l’organisme.</p>
<p>J’ai récemment migré l’intégralité des certificats <span class="caps">SSL</span> utilisés sur
<a href="phyks.me">phyks.me</a> et ses sous-domaines, pour passer de
<a href="http://startssl.com/">StartSSL</a> à <a href="https://letsencrypt.org/">Let’s Encrypt</a>,
principalement suite à <a href="https://docs.google.com/document/d/1C6BlmbeQfn4a9zydVi2UvjBGv6szuSB4sMYUcVrR8vQ/edit">cette annonce de
Mozilla</a>.
Je n’ai jamais payé pour un certificat <span class="caps">SSL</span> depuis que j’ai ce nom de domaine
(StartSSL, tout comme Let’s Encrypt les fournissent gratuitement), tandis que
les autorités facturent jusqu’à 100$ le certificat.</p>
<p>Ce mois-ci, c’est donc 25$ qui <a href="https://eff.org/donate-le">vont à l’<span class="caps">EFF</span></a>
principalement pour leur soutien à Let’s Encrypt et leur
<a href="https://github.com/certbot/certbot">certbot</a> qui facilite énormément la
gestion de ses certificats. L’<span class="caps">EFF</span> s’engage également pour <a href="https://www.eff.org/issues/free-speech">défendre la liberté
d’expression sur le net</a>, pour <a href="https://www.eff.org/issues/intellectual-property">lutter
contre les brevets
logiciels</a> et <a href="https://www.eff.org/fr/issues/drm">contre les
DRMs</a>, ainsi que sur les questions de <a href="https://www.eff.org/issues/privacy">vie
privée</a>. Ils sont également derrière un
<a href="https://www.eff.org/about/opportunities/volunteer/coding-with-eff">certain nombre de logiciels et
extensions</a>
tels que <a href="https://www.eff.org/https-everywhere"><span class="caps">HTTPS</span> Everywhere</a>.</p>Moving from URxvt to st2016-08-07T22:20:00+02:002016-08-07T22:20:00+02:00Phykstag:localhost,2016-08-07:/Blog/output/2016/08/moving-from-urxvt-to-st.html<p>I have been using <code>URxvt</code> terminal for a while, but was suffering many issues
with it recently. In particular, I had a weird locale issue, leading to
unicode encoding errors whenever I copy accentuated characters using primary
keyboard, <a href="https://github.com/majutsushi/urxvt-font-size/issues/10">some weird
issues</a> due to
<code>urxvt-tabbed</code> and it just blew up when …</p><p>I have been using <code>URxvt</code> terminal for a while, but was suffering many issues
with it recently. In particular, I had a weird locale issue, leading to
unicode encoding errors whenever I copy accentuated characters using primary
keyboard, <a href="https://github.com/majutsushi/urxvt-font-size/issues/10">some weird
issues</a> due to
<code>urxvt-tabbed</code> and it just blew up when I tried to get new unicode characters
right in it (such as smileys).</p>
<p>A friend told me about <a href="http://st.suckless.org/">st</a> which may be quite
daunting at first, especially since all the configuration is made statically
in a C header file, but it is working incredibly well, and just doing the job fine.</p>
<p>I have <a href="https://git.phyks.me/Phyks/st">a mirror repo</a> with my own
configuration in case you want to have a look at it. This reproduces most of
my <code>URxvt</code> user experience, except from two things:</p>
<ol>
<li>I don’t have any tabs in <code>st</code>. But this is not a real issue and I’d rather
depend on another program to handle tabs, such as <code>tmux</code> or even <code>i3</code>.</li>
<li>I don’t have clickable URLs as I used to have in <code>URxvt</code>. But once again,
after a few weeks without this feature, I prefer selecting and copy/pasting
URLs rather than clicking on them. This way, I don’t open links unintentionally.</li>
</ol>
<p>I was relying on <a href="http://localhost/Blog/output/2014/02/local-notifications-for-weechat-and-urxvt.html">a hack</a> to get
local notifications for my Weechat running through <code>SSH</code> + <code>screen</code>, using an
extended escape sequence, and if you are also using it <a href="https://git.phyks.me/Phyks/st/commit/2da862562efb6173e4c203365bc028e902adce2b">this
commit</a>
will implement this behavior in <code>st</code>.</p>Improved back and forth between workspaces2016-05-29T19:34:00+02:002016-05-29T19:34:00+02:00Phykstag:localhost,2016-05-29:/Blog/output/2016/05/improved-back-and-forth-between-workspaces.html<p>i3 has <a href="https://i3wm.org/docs/userguide.html#_automatic_back_and_forth_when_switching_to_the_current_workspace">a
feature</a>
to enable going back and forth between workspaces. Once enabled, if you are on
workspace 1 and switch to workspace 2 and then just press <code>mod+2</code> again to
switch to workspace 2, you will go back to workspace 1.</p>
<p>However, this feature is quite limited …</p><p>i3 has <a href="https://i3wm.org/docs/userguide.html#_automatic_back_and_forth_when_switching_to_the_current_workspace">a
feature</a>
to enable going back and forth between workspaces. Once enabled, if you are on
workspace 1 and switch to workspace 2 and then just press <code>mod+2</code> again to
switch to workspace 2, you will go back to workspace 1.</p>
<p>However, this feature is quite limited as it does not remember more than one
previous workspace. For example, say you are on workspace 1, switch to
workspace 2 and then to workspace 3. Then, typing <code>mod+3</code> will send you back
to workspace 2 as expected. But then, typing <code>mod+2</code> will send you back to
workspace 3 whereas one may have expected it to switch to workspace 1 (as does
Weechat with buffers switch for instance).</p>
<p>This can be solved by wrapping around the workspace switching in the i3
config. I wrote <a href="https://gist.github.com/Phyks/4fbc2572dcc5eed96caa">this small
script</a> to handle it.</p>
<p>Basically, you have to start the script when you start i3 by putting</p>
<div class="highlight"><pre><span></span><code>exec_always<span class="w"> </span>--no-startup-id<span class="w"> </span><span class="s2">"python PATH_TO_/workspace_back_and_forth_enhanced.py"</span>
</code></pre></div>
<p>in your <code>.i3/config</code> file.</p>
<p>Then, you can replace your <code>bindsym</code> commands to switch workspaces, calling
the same script:</p>
<div class="highlight"><pre><span></span><code>bindsym<span class="w"> </span><span class="nv">$mod</span>+agrave<span class="w"> </span><span class="nb">exec</span><span class="w"> </span><span class="s2">"echo 10 | socat -</span>
<span class="s2">UNIX-CONNECT:</span><span class="nv">$XDG_RUNTIME_DIR</span><span class="s2">/i3/i3-back-and-forth-enhanced.sock"</span>
</code></pre></div>
<p>(Replace <code>$XDG_RUNTIME_DIR</code> by <code>/tmp</code> if this environment variable is not
defined on your system.)</p>
<p>This script does maintain a queue of 20 previously seen workspaces (so you can
go back 20 workspaces ago in your history). This can be increased by editing
the <code>WORKSPACES_STACK = deque(maxlen=20)</code> line according to your needs.</p>
<p>Hope this helps! :)</p>Comparison of tools to fetch references for scientific papers2016-01-19T14:45:00+01:002016-01-19T14:45:00+01:00Phykstag:localhost,2016-01-19:/Blog/output/2016/01/comparison-of-tools-to-fetch-references-for-scientific-papers.html<p>Recently, I tried to aggregate in <a href="https://github.com/Phyks/libbmc/">a single place</a> various codes I had written to handle scientific papers. Some feature I was missing, and I would like to add, was the ability to fetch automatically references from a given paper. For arXiv papers, I had a <a href="http://localhost/Blog/output/2015/12/lets-add-some-metadata-on-arxiv.html">simple solution</a> using the …</p><p>Recently, I tried to aggregate in <a href="https://github.com/Phyks/libbmc/">a single place</a> various codes I had written to handle scientific papers. Some feature I was missing, and I would like to add, was the ability to fetch automatically references from a given paper. For arXiv papers, I had a <a href="http://localhost/Blog/output/2015/12/lets-add-some-metadata-on-arxiv.html">simple solution</a> using the LaTeX sources, but I wanted to have something more universal, taking a simple <span class="caps">PDF</span> file in input (thanks <a href="https://www.linkedin.com/in/john-dove-a8825">John</a> for the suggestion, and <a href="http://www.alstevens.org/">Al</a> for the tips on existing software solutions).</p>
<p>I tried a comparison of three existing software to extract references from a <span class="caps">PDF</span> file:</p>
<ul>
<li><a href="https://github.com/CrossRef/pdfextract">pdfextract</a> from Crossref, very easy to use, written in Ruby.</li>
<li><a href="https://github.com/kermitt2/grobid">Grobid</a>, more advanced (using machine learning models), written in Java, but quite easy to use too.</li>
<li><a href="https://github.com/CeON/CERMINE">Cermine</a>, using the same approach as Grobid, but I could not get it to build on my computer. I used their <a href="http://cermine.ceon.pl/index.html"><span class="caps">REST</span> service</a> instead.</li>
</ul>
<p>To compare them, I asked <a href="http://antonin.delpeuch.eu/">Antonin</a> to build a list of most important journals and take five papers for every such journal, from <a href="http://dissem.in/">Dissemin</a>. This gives us a <a href="http://pub.phyks.me/paper_references_extractor/papers.json"><span class="caps">JSON</span> file</a> containing around 500 papers.</p>
<p>I downloaded some articles, to get a (hopefully) representative set, composed of 147 different papers from various journals (I did not had access to some of them, so I could not fetch the full dataset). I ran <code>pdfextract</code>, <code>Grobid</code> and <code>Cermine</code> on each of them and compared the results.</p>
<p>The raw results are available <a href="http://pub.phyks.me/paper_references_extractor/">here</a> for each paper, and I generated a single page comparison to ease the visual diff between the three results, available <a href="http://pub.phyks.me/paper_references_extractor/diff.html">here</a> (note that this webpage is <strong>very</strong> heavy, around <span class="caps">16MB</span>).</p>
<p>Briefly comparing the results, the machine learning based models (Cermine and Grobid) seems to give far better results than the simple approach taken by pdfextract, at the expense of being more difficult to build and run. Cermine gives a bunch of infos, too much in my opinion, and I think Grobid is given the most reusable and complete results. Feel free to compare them yourself.</p>
<p><strong><span class="caps">EDIT</span></strong>:</p>
<ul>
<li>
<p>I also found <a href="https://github.com/knmnyn/ParsCit">ParsCit</a> which may be
of interest. Though, you first need to extract text from your <span class="caps">PDF</span> file. I did
not yet test it more in depth.</p>
</li>
<li>
<p><a href="https://twitter.com/_krisjack/status/736490898192764928">This tweet</a> tends
to confirm the results I had, that Grobid is the best one.</p>
</li>
<li>
<p>If it can be useful, <a href="https://github.com/Phyks/CitationExtractor">here</a> is a
small web service written in Python to allow a user to upload a paper and
parse citations and try to assess open-access availability of the cited
papers. It uses <span class="caps">CERMINE</span> as it was the easiest way to go, especially since it
offers a web <span class="caps">API</span>, which allows me to distribute a simply working script,
without any additional requirements.</p>
</li>
</ul>Localizing a webapp with webL10n.js2015-12-26T23:17:00+01:002015-12-26T23:17:00+01:00Phykstag:localhost,2015-12-26:/Blog/output/2015/12/localizing-a-webapp-with-webl10njs.html<p>I am currently working on a <a href="https://github.com/hackEns/VelibFxos">Velib webapp</a>. With <a href="http://blog.exppad.com/">Élie</a>, we modularized everything so that the backend <span class="caps">API</span> can be edited easily, and adapted to any other bike sharing system, hence we wanted it to be easily localizable and looked for solutions compatible with as much browsers as possible. We …</p><p>I am currently working on a <a href="https://github.com/hackEns/VelibFxos">Velib webapp</a>. With <a href="http://blog.exppad.com/">Élie</a>, we modularized everything so that the backend <span class="caps">API</span> can be edited easily, and adapted to any other bike sharing system, hence we wanted it to be easily localizable and looked for solutions compatible with as much browsers as possible. We finally chose <a href="https://github.com/fabi1cazenave/webL10n">webL10n.js</a>. Here are some explanations about it and how to use it.</p>
<h2>Why webL10n.js?</h2>
<p>First thing is: why choosing webL10n.js instead of anything else? We found basically four solutions: <a href="https://github.com/fabi1cazenave/webL10n">webL10n.js</a>, <a href="https://github.com/l20n/l20n.js">L20n.js</a>, <a href="https://github.com/SlexAxton/Jed">Jed</a> and <a href="https://github.com/mozilla-b2g/gaia/blob/master/shared/js/l10n.js">a modified version of webL10n.js</a> used in Gaia.</p>
<p>Jed takes a really different approach and, especially as we are not really familiar with localizing content, we found it more difficult to use and integrate.</p>
<p>The three others take a really simple approach. They use extra <code>data-*</code> attribute on any tag to replace on the fly the <code>textContent</code> of the node by a translation found in a formatted file. It is really easy to integrate, use and tweak. They support advanced features such as pluralization, <span class="caps">HTML</span> modifications, responsive localization (to use a different localization file on small screens), etc.</p>
<p>WebL10n.js and the modified version in Gaia are basically the same, except that the one in Gaia dropped hacks to add support in some old browsers such as <span class="caps">IE6</span>. Plus webL10n is in a separate git repo which is easy to track, so I’d rather go with this one. But the documentation is not really complete and <a href="https://developer.mozilla.org/en-US/Apps/Build/Localization/Getting_started_with_app_localization#Add_l10n.js">the associated <span class="caps">MDN</span> wiki page</a> is outdated. Hence this blog post :) Don’t worry about the lack of recent commits on webL10n.js, it is stable and usable (and still maintained and supported by <a href="http://www.fabiencazenave.org/">kaze</a>).</p>
<p>L20n.js is the latest Mozilla project aiming at replacing webL10n.js. I had many problems with it, because the <span class="caps">API</span> keeps moving, and no doc is in sync with the code. Downloadable version exposes a totally different <span class="caps">API</span> than the one in the git repo, and the doc is not really helpful concerning which version should be considered stable. Plus the <code>l20n</code> file format is really weird and I’d rather not reinvent the wheel and go with standard <code>properties</code> file to ease translation for contributors.</p>
<h2>Demo and extra infos</h2>
<p>For more informations, you can refer to the <a href="https://github.com/fabi1cazenave/webL10n/blob/master/README.md"><span class="caps">README</span></a>.</p>
<p>For an app using it, you can have a look at <a href="https://github.com/hackEns/VelibFxos">our VelibFxos webapp</a>, espcially <a href="https://github.com/hackEns/VelibFxos/blob/v2/l10n/">this folder</a>. You can also see it in your browser at <a href="https://velib.phyks.me/">https://velib.phyks.me/</a> (under heavy work in progress, so might break from time to time).</p>
<p><em>Note</em>: Note that there is a bug when mixing pluralization and <code>innerHTML</code>, which can be worked around. See <a href="https://github.com/fabi1cazenave/webL10n/issues/75">this Github issue</a>.</p>Let’s add some metadata on arXiv!2015-12-26T18:50:00+01:002015-12-26T18:50:00+01:00Phykstag:localhost,2015-12-26:/Blog/output/2015/12/lets-add-some-metadata-on-arxiv.html<p>This article contains ideas and explanations around <a href="https://github.com/Phyks/arxiv_metadata">this code</a>. Many references to it will be done through this article.</p>
<p>Disclaimer: The above code is here as a proof of concept and to back this article with some code. It is clearly not designed (nor scalable) to run in production. However …</p><p>This article contains ideas and explanations around <a href="https://github.com/Phyks/arxiv_metadata">this code</a>. Many references to it will be done through this article.</p>
<p>Disclaimer: The above code is here as a proof of concept and to back this article with some code. It is clearly not designed (nor scalable) to run in production. However, the <code>reference_fetcher</code> part was giving good results on the arXiv papers I tested it on.</p>
<p>Nowadays, most of the published scientific papers are available online, either directly on the publisher’s website, or as preprints on <a href="https://en.wikipedia.org/wiki/Open_access">Open access</a> repositories. For physics and computer science, most of them are available on the <a href="http://arxiv.org">arXiv.org</a> repository (a major, worldwide, Open access repository managed by Cornell). All published papers get a unique (global) identifier, called a <a href="https://en.wikipedia.org/wiki/Digital_object_identifier"><span class="caps">DOI</span></a>, which can be used to identify them and link to them. For instance, if one gets to <a href="https://dx.doi.org/10.1103%2FPhysRevB.47.7312">https://dx.doi.org/10.1103%2FPhysRevB.47.7312</a> it is automatically redirected to the Physical Review B website, on the page of the paper with <span class="caps">DOI</span> <code>10.1103%2FPhysRevB.47.7312</code>. This is really useful to target a paper, and identify it uniquely, in a machine-readable way and in a way that will last. However, very little use seems to be done of this system. This is why I had the idea to put some extra metadata on published papers, using such systems.</p>
<p>From now on, I will mainly focus on arXiv for two main reasons. First, it is Open access, so it is accessible everywhere (and not depending on the rights from a particular institution) and reusable, and second, arXiv provides sources for most of the papers, which is of great interest as we will see below. arXiv gives a unique <a href="https://arxiv.org/help/arxiv_identifier">identifier</a> to the preprints. Correspondence between DOIs and arXiv identifiers can be made quite easily as some publishers push back <span class="caps">DOI</span> to arXiv upon publication, and authors manually update the fields on arXiv for the rest of the publishers.</p>
<p>Using services such as <a href="http://search.crossref.org/">Crossref</a> or the publisher’s website, it is really easy to get a formatted bibliography (plaintext, BibTeX, …) from a given identifier (e.g. see some codes for <a href="https://github.com/Phyks/BMC/blob/master/libbmc/fetcher.py#L27://github.com/Phyks/BMC/blob/master/libbmc/fetcher.py#L275"><span class="caps">DOI</span></a> or <a href="https://github.com/Phyks/BMC/blob/master/libbmc/fetcher.py#L305">arXiv id</a> for BibTeX output). Then, writing a bibliography should be as easy as keeping track of a list of identifiers!</p>
<h2>Let’s make a graph of citations!</h2>
<p>In scientific papers, references are usually a plaintext list of papers used as reference, at the end of the article. This list follows some rules and formats, but there exist a wide variety of different formats, and it is often really difficult to parse them automatically (see <a href="http://arxiv.org/abs/1506.06690">http://arxiv.org/abs/1506.06690</a> for an example of references format).</p>
<p>If one wants to fetch automatically the references from a given paper (to download them in batch for instance), he would basically have to parse a <span class="caps">PDF</span> file, find the references section, and parse each textual item, which is really difficult and error-prone. Some repositories, such as arXiv, offers sources for the published preprints. In this case, one can deal with a LaTeX-formatted bibliography (a <code>thebibliography</code> environment, not a full BiBTeX though), which is a bit better, but still a pity to deal with. When referencing an article, nobody uses DOIs!</p>
<p>First idea is then to try to automatically fetch references for arXiv preprints and mark them as relationships between articles.</p>
<p>Fortunately, arXiv provides <code>bbl</code> source files for most of the articles (which are LaTeX-formatted bibliography). We can them avoid having to parse a <span class="caps">PDF</span> file, and directly get some structured text, but bibliography is still in plaintext, without any machine-readable identifier. Here comes <a href="http://search.crossref.org/">Crossref</a> which offers a wonderful <span class="caps">API</span> to try to fetch a <span class="caps">DOI</span> from a plain text (see <a href="http://labs.crossref.org/resolving-citations-we-dont-need-no-stinkin-parser/">http://labs.crossref.org/resolving-citations-we-dont-need-no-stinkin-parser/</a>). And it gives surprisingly good results!</p>
<p>This automatic fetching of <span class="caps">DOI</span> for references of a given arXiv papers is available <a href="https://github.com/Phyks/arxiv_metadata/blob/master/fetch_references">in this code</a>.</p>
<p>Then, one can simply write a simple <span class="caps">API</span> accepting <code>POST</code> requests to add papers to a database, fetch referenced papers, and mark relationships between them. This is how <a href="https://github.com/Phyks/arxiv_metadata">https://github.com/Phyks/arxiv_metadata</a> began.</p>
<p>If you post a paper to it, identified either by its <span class="caps">DOI</span> (and a valid associated arXiv id is found) or directly by its arXiv id, it will add it to the database, resolve its references and mark relationships in database between this paper and the references papers. One can then simply query the graph of “citations”, in direct or reverse order, to get any papers cited by a given one, or citing a given one.</p>
<p>The only similar service I know of on the web is the one provided by <span class="caps">SAO</span>/<span class="caps">NASA</span> <span class="caps">ADS</span>. See for instance <a href="http://adsabs.harvard.edu/cgi-bin/bib_query?arXiv:1506.06690">how it deals with the introductory paper</a>. It is quite fantastic for giving both the papers citing this one and cited by this one, in a browsable form, but its core is not open-source (or I did not find it), and I have no idea how it works in the background. There is no easily accessible <span class="caps">API</span>, and it works only in some very specific fields (typically Physics).</p>
<h2>Let’s add even more relations!</h2>
<p>Now that we have a base <span class="caps">API</span> to add papers and relationships between them to a database, we can imagine going one step further and mark any kind of relations between the papers.</p>
<p>For instance, one can find that a given paper could be another reference for another one, which was not citing it. We could then collaboratively work to put extra metadata on scientific papers, such as extra references, which would be useful to everyone.</p>
<p>Such relationships could also be <code>similar to</code>, <code>introductory_course</code>, etc. This is quite limitless and the above code can already handle it. :)</p>
<h2>Let’s go one step further and add tags!</h2>
<p>So, by now, we can have uniquely identified papers, with any kind of
relationships between them, which we can crowdsource. Let’s take some time to
look at how arXiv stores papers.</p>
<p>They classify them by “general categories” (e.g. <code>cond-mat</code> which is a (very) large category called “Condensed Matter”) and subcategories (e.g. <code>cond-mat.quant-gas</code> for “Quantum gases” under “Condensed Matter”). A <span class="caps">RSS</span> feed is offered for all these categories, and researchers usually follow the subcategory of their research area to keep up to date with published articles.</p>
<p>Although some article are released under multiple categories, most of them only have one category, very often because they do not fit anywhere else, but sometimes because the author did not think it could be relevant in another field. Plus some researchers work at the edge of two fields, and following everything published in these two fields is a very time-consuming task.</p>
<p>Next step is then to collaboratively tag articles. We could get tags as targeted as we want, or as general as we want, and everyone could follow the tags they want. Plus doing it collaboratively allows someone who finds an article interesting for its field, which was not the author’s field, to make it appear in the feed of his colleagues.</p>
<h2>Conclusion</h2>
<p>We finally have the tools to mark relations between papers, to annotate them, complete them, and tag them. And all of this collaboratively. With DOIs and similar unique identifiers, we have the ability to get rid of the painful plaintext citations and references and use easily machine-manageable identifiers, while still getting some nicely rendered BibTeX citations automagically.</p>
<p>People are already doing this kind of things for webpages (identified by their <span class="caps">URL</span>) with <a href="http://reddit.com/">Reddit</a> or <a href="https://news.ycombinator.com/">HackerNews</a> and so on, let’s do the same for scientific papers! :)</p>
<p>A demo instance should be available at <a href="http://arxiv.phyks.me/">http://arxiv.phyks.me/</a>. This may not be very stable or highly available though.</p>
<p><strong><span class="caps">EDIT</span> (14/05/2017):</strong> The demo instance is no longer available. But the repo
is still <a href="https://github.com/Phyks/arxiv_metadata">out there</a> if you want to
give it a try!</p>Velib dataset2015-11-12T18:50:00+01:002015-11-12T18:50:00+01:00Phykstag:localhost,2015-11-12:/Blog/output/2015/11/velib-dataset.html<p>Just a quick note to say that I am running a script to periodically dump the
data available from the Velib <span class="caps">API</span> (every 2 minutes).</p>
<p>The dump can be found <a href="http://pub.phyks.me/datasets/velib.db">here</a> (sqlite3
database). It is generated by <a href="https://github.com/Phyks/VelibDataSet/">this
script</a>.</p>
<p>Please host your own if you plan on making many queries …</p><p>Just a quick note to say that I am running a script to periodically dump the
data available from the Velib <span class="caps">API</span> (every 2 minutes).</p>
<p>The dump can be found <a href="http://pub.phyks.me/datasets/velib.db">here</a> (sqlite3
database). It is generated by <a href="https://github.com/Phyks/VelibDataSet/">this
script</a>.</p>
<p>Please host your own if you plan on making many queries against the previous
<span class="caps">URL</span>.</p>
<p><strong>Update</strong>: As of 27/08/2017, I updated the way Velib <span class="caps">API</span> data is stored and
available as a dump. All the available dumped data are available
<a href="https://pub.phyks.me/datasets/velib/">here</a> and you should refer to the
<a href="https://pub.phyks.me/datasets/velib/README.txt"><code>README.txt</code></a> file for up to
date information on the available datasets.</p>Doing low cost telepresence (for under $200)2015-10-08T23:08:00+02:002015-10-08T23:08:00+02:00Phykstag:localhost,2015-10-08:/Blog/output/2015/10/doing-low-cost-telepresence-for-under-200.html<p>With <a href="http://exppad.com/">a friend</a>, we recently started a project of building a project of <a href="http://known.hackens.org/2015/nouveau-projet-disty-robot-de-tlprsence">low cost telepresence robot</a> (sorry, link in French only).</p>
<p>The goal is to build a robot that could be used to move around a room remotely, and stream audio and video in both directions. Our target budget …</p><p>With <a href="http://exppad.com/">a friend</a>, we recently started a project of building a project of <a href="http://known.hackens.org/2015/nouveau-projet-disty-robot-de-tlprsence">low cost telepresence robot</a> (sorry, link in French only).</p>
<p>The goal is to build a robot that could be used to move around a room remotely, and stream audio and video in both directions. Our target budget is $200. We got a first working version (although it does not yet stream audio), and it is time for some explanations on the setup and how to build your own =) All the instructions, code and necessary stuff can be found at <a href="http://git.eleves.ens.fr/hackens/Disty">our git repo</a>.</p>
<p><img alt="Screen capture" src="https://raw.githubusercontent.com/hackEns/Disty/master/doc/screenshot.png"></p>
<hr/>
<p><img alt="3D model" src="https://raw.githubusercontent.com/hackEns/Disty/master/doc/3Dmodel.png"></p>
<h2>Basic idea</h2>
<p>When taking part in a group meeting remotely, using some videoconference solution, it is often frustrating not being able to move around the room on the other side. This prevents us from having parallel discussions, and if the remote microphone is poor quality, we often do not hear clearly everybody speaking. Plus, someone speaking may be hidden by another speaker and many other such problems happen.</p>
<p>The goal was then to find a solution to do videoconferences (streaming both audio and video in both directions) and be able to move on the other side, to be able to see everyone and to come closer to the current speaker. Commercial solutions <a href="http://www.wired.com/images_blogs/business/2014/03/snowden_ted.jpg">exist</a> but they are really expensive (a few thousands dollars). We wanted to have the same basic features for $200, and it seems we almost achieved it!</p>
<h2>Bill of Materials</h2>
<p>The whole system is built around a Raspberry Pi and a PiCamera, which offer decent performances at a very fair price. The rest is really basic <span class="caps">DIY</span> stuff.</p>
<p>Here is the complete bill of materials:</p>
<ul>
<li>A Raspberry Pi 2 - $30</li>
<li>A PiCamera - $30</li>
<li>2 <a href="http://www.amazon.com/gp/product/B00P7N0320?keywords=Anker%20Astro%20E1%205200mAh&qid=1444342471&ref_=sr_1_1&sr=8-1">external <span class="caps">USB</span> battery packs</a> - 2 * $15.99 ≈ $30</li>
<li>2 <a href="https://www.adafruit.com/products/154">continuous rotation servo</a> for the wheels - 2 * $11.95 = $25</li>
<li>2 <a href="https://www.adafruit.com/products/167">servo wheels</a> - 2 * $4 = $8</li>
<li>1 <a href="https://www.adafruit.com/products/155">standard servo</a> for the camera control - $12</li>
<li>1 wifi <span class="caps">USB</span> adapter - $5</li>
<li>2 ball transfer unit</li>
<li>Some plexiglas and <span class="caps">ABS</span> for laser cutting and 3D printing</li>
</ul>
<p>Total: $140</p>
<p>Notes:
* We had to use a Raspberry Pi model 2 for the nice performance boost on this model. Even more important is the increased number of GPIOs on this model, with 2 usable hardware PWMs (provided that you don’t use the integrated sound card output). This is useful to control the two wheels with hardware <span class="caps">PWM</span> and have a precise control of the move. The camera holder can be safely controlled with a software <span class="caps">PWM</span> and we did not experience any troubles doing so.
* You can easily replace those parts by equivalent ones as long as you keep in mind that the battery pack should be able to provide enough current for the raspberry pi and the servos. We used standard <span class="caps">USB</span> battery packs for simplicity and user friendliness. However, they are more expensive than standard modelling lithium batteries and provide less current in general.
* We had to use two battery packs. Indeed, the peak current due to the servos starting was too excessive for the battery pack and it was crashing the raspberry pi. Using two separate alimentation lines for the raspberry pi and the servos, we no longer have this problem and this solution is easier than tweaking the alimentation line until the raspberry pi stops freezing (which it may never do).</p>
<p>For the next version, we plan to add:
* 1 <a href="https://www.adafruit.com/products/2232">small 5” <span class="caps">HDMI</span> screen</a> - $59.95
* 1 <a href="http://www.amazon.com/gp/product/B00YTXPY6Y?keywords=taotronics%20speaker&qid=1444343334&ref_=sr_1_1&sr=8-1">bluetooth speaker with integrated mic</a> - $14
* 1 <a href="http://www.amazon.com/ASUS-USB-Adapter-Bluetooth-USB-BT400/dp/B00DJ83070">usb bluetooth adapter</a> for the speakers - $14</p>
<p>Total with these parts: $228</p>
<p>Notes:
* We used an <span class="caps">HDMI</span> screen as the official RaspberryPi screen uses most of the GPIOs pins, which we need.
* We decided to use bluetooth speakers as the integrated sound card was not usable as we were using the two hardware <span class="caps">PWM</span> lines for motion. This way, we have a speaker with a built-in microphone, which smaller than having the two of them separately.
* The <span class="caps">USB</span> bluetooth adapter is impressively expensive, but it is the only one we found at the moment which we were sure would be compatible with Linux without any problems. Plus others adapters we found were not much cheaper.
* The total budget is $223 without shipping. It is a bit over the initial budget goal, but we can easily lower it to $200. Indeed, we did not especially look for the cheaper parts. In particular, we bought the servos from Adafruit and I think we can find some servos for less (especially the camera holder servo, which can be a micro servo at $5 and should be enough). The bluetooth adapter is quite expensive as well and we could find a cheaper one I think. Budget shrinkage will be our next goal, once we have everything working.</p>
<h2>Building the robot</h2>
<p>All the necessary stuff is in our <a href="https://git.eleves.ens.fr/hackens/Disty">git repo</a> (or its <a href="https://github.com/hackEns/Disty">github mirror</a>, both should be kept in sync). The repo contains three main directories:
- <code>blueprints</code> which are the models of the robot.
- <code>disty</code> which is the main server code on the Raspberry Pi.
- <code>webview</code> which is the web controller served by the Raspberry Pi.</p>
<p>First of all, you should cut the parts and print the 3D parts in the <code>blueprints</code> dir. <code>eps</code> files in this directory are ready to cut files whereas <code>svg</code> files should be the same ones in easily editable format. You should laser cut the top and bottom files. <code>picam_case_*</code> files are the camera case we used,</p>
<p>You should 3D print:
* the <code>picam_case_*</code> files for the camera case (licensed under <span class="caps">CC</span> <span class="caps">BY</span> <span class="caps">SA</span>).
* <code>teleprez.blend</code> is the complete <span class="caps">CAO</span> model of the robot in Blender.
* <code>camera_servo_holder.stl</code> is the plastic part to hold the camera servo. You
need to print it once.
* <code>wheel_servo_holder.stl</code> is the plastic part to hold the servos for the
wheels. You need four of them.</p>
<p>Assembling your Disty robot should be straightforward and easy to do if you look at the following pictures :) Use two ball transfer units to stabilize the robot and lock them with some rubber band (or anything better than that). Adjust tightly the height of the wheels so that the two wheels and the ball transfer units touch the ground.</p>
<p><img alt="Disty" src="http://pub.hackens.org/images/disty/disty1.jpg"></p>
<p><img alt="Disty" src="http://pub.hackens.org/images/disty/disty2.jpg"></p>
<p><img alt="Disty" src="http://pub.hackens.org/images/disty/disty3.jpg"></p>
<p><span class="caps">GPIO</span> pinout for the connection can be found at https://raw.githubusercontent.com/hackEns/Disty/master/blueprints/gpio.png.</p>
<p><img alt="GPIO pinout" src="https://raw.githubusercontent.com/hackEns/Disty/master/blueprints/gpio.png"></p>
<p>For the electrical wiring, we used a standard <span class="caps">USB</span>-Micro <span class="caps">USB</span> cable to power the Raspberry Pi from one battery (located below the robot, to add weight on the ball transfer units and ensure contact is made with the surface). On the other battery, we just cut a <span class="caps">USB</span> - Micro <span class="caps">USB</span> cable to plug into it and connect the servos directly through a piece of breadboard to the battery. We had to use two batteries to prevent the draw from the servos to reboot the Raspberry Pi.</p>
<p>Here you are, you have a working Disty!</p>
<h2>Running it</h2>
<p>This may not be super user-friendly at the moment, we hope to improve this in the future.</p>
<p>Download any Linux image you want for your Raspberry Pi. Install <code>uv4l</code> and the <code>uv4l-webrtc</code> component. Enable the camera and ensure you can take pictures from the command line (there is a lot of doc) about this on the web.</p>
<p>Then, clone the Git repo somewhere on your Raspberry Pi. You should build the main <code>disty</code> code (which is the serverside code). This code will handle the control of the servos (emit PWMs etc) and listen on <span class="caps">UDP</span> port 4242 for instructions sent from the webview. Instructions to build it are located in the associated <span class="caps">README</span>. You will need <code>cmake</code> and a system-wide install of <code>wiringpi</code> to build the code.</p>
<p>You can then start the robot. Start by launching the disty program (as root as you need access to the GPIOs), <code>./disty</code>, and then start the webview, <code>./run.py</code> as root also as it serves the webview on port 80, which is below 1024 and owned by root. If you have ZeroConf on your Raspberry Pi (or a decent router), you can go to http://disty (or whatever hostname is set on your Raspberry Pi) to get the webview. Else, use the <span class="caps">IP</span> address instead. Webview usage should be almost straightforward.</p>
<p>It should work out of the box on your local <span class="caps">LAN</span>. If you are behind a <span class="caps">NAT</span>, it will need some black magic (which is implemented but may not be sufficient) to connect the remote user and Disty camera. In any case, you need to be able to access the webview (disty port 80) from the remote side.</p>
<h2>Contributing!</h2>
<p>All contributions and feedbacks are more than welcomed!</p>
<p>All the source code we wrote is under a beer-ware license, under otherwise specified.</p>
<blockquote>
<hr>
<p><span class="dquo">“</span><span class="caps">THE</span> <span class="caps">BEER</span>-<span class="caps">WARE</span> <span class="caps">LICENSE</span>” (Revision 42):
Phyks and Élie wrote this file. As long as you retain this notice you
can do whatever you want with this stuff (and you can also do whatever you want
with this stuff without retaining it, but that’s not cool…). If we meet some
day, and you think this stuff is worth it, you can buy us a beer
in return. hackEns</p>
<hr>
</blockquote>
<p>If you need a more legally valid license, you can consider Disty to be under an <span class="caps">MIT</span> license.</p>
<h2>Some sources of inspiration and documentation</h2>
<ul>
<li><a href="http://www.pcmag.com/article2/0,2817,2427997,00.asp">http://www.pcmag.com/article2/0,2817,2427997,00.asp</a>, cool but really expensive!</li>
<li><a href="http://josh.com/notes/bitlybot/">http://josh.com/notes/bitlybot/</a>, a really basic telepresence robot</li>
<li><a href="https://known.phyks.me/2015/controlling-servomotors-on-a-raspberry-pi">https://known.phyks.me/2015/controlling-servomotors-on-a-raspberry-pi</a>, for the problems we encountered with the servos on the Raspberry Pi</li>
<li><a href="http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/">http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/</a></li>
</ul>Working on the go in Paris2015-10-08T23:08:00+02:002015-10-08T23:08:00+02:00Phykstag:localhost,2015-10-08:/Blog/output/2015/10/working-on-the-go-in-paris.html<p>This summer I was in <span class="caps">NYC</span> and found a couple of nice coffee shops with good
coffee and internet access so that they were suitable for work. Coming back to
Paris, I started looking for similar places. This post will be updated in the
future with the new places I …</p><p>This summer I was in <span class="caps">NYC</span> and found a couple of nice coffee shops with good
coffee and internet access so that they were suitable for work. Coming back to
Paris, I started looking for similar places. This post will be updated in the
future with the new places I find.</p>
<ul>
<li><a href="http://www.yelp.com/biz/coutume-instituutti-paris-2">Coutume Instituutti</a>
is a really cool coffee shop in the 5th, near Saint-Michel. Good coffee, the
place is very cool and I always found a decent place to sit and work.</li>
<li><a href="http://www.anticafe.eu/">Anticafé</a> is a brand of really cool coffee shops
in Paris (near le Louvres, near Beaubourg and near Bibliothèque François
Mitterrand). Fun fact is that you pay for the time you stay (5€ per hour,
and decreasing) and everything is free afterwards (food and drink). Really
nice to work!<ul>
<li>The one near le Louvres is really nice, although it can be crowded.</li>
<li>The one near Bibliothèque François Mitterrand has plenty of seats and
offers some food as well, which is cool. However, the internet is really
bad there, since you have very basic and limited internet (Web + emails
only). Most of the port are blocked, including <span class="caps">TCP</span> 22 for ssh, and it
can be really difficult to work with web and emails only (in my case, at
least) =(</li>
<li>I still should test the one near Beaubourg.</li>
</ul>
</li>
<li><a href="http://www.sugarplumcakeshop.com/fr/">Sugarplum</a> is a cool coffee in the
5th, near Mouffetard. Nice coffee and cake, and there are many tables. The
wifi is ok, but not really fast, and I did not notice power plugs.</li>
</ul>
<p>To be tested in the future:
<a href="http://blog.we-paris.com/insolite-paris/hubsy-cafe-coworking-du-3e-arrondissement/">http://blog.we-paris.com/insolite-paris/hubsy-cafe-coworking-du-3e-arrondissement/</a>,
<a href="http://www.yelp.fr/biz/strada-caf%C3%A9-paris">http://www.yelp.fr/biz/strada-caf%C3%A9-paris</a>.</p>Nice places to work around2015-08-24T23:08:00+02:002015-08-24T23:08:00+02:00Phykstag:localhost,2015-08-24:/Blog/output/2015/08/nice-places-to-work-around.html<h2>In <span class="caps">NYC</span></h2>
<p>Just a note to myself, to remember some good places to work I found in <span class="caps">NYC</span>.
Might be useful for others :)</p>
<ul>
<li><a href="http://www.brooklynroasting.com/">Brooklyn Roasting Company</a> on Jay Street,
really cool place, good wifi, nice coffee and power outlets.</li>
<li><a href="https://www.facebook.com/pages/Black-Brick-Coffee/281642998540673">Black
brick</a> on
Bedford ave, really cool place, darker and smaller …</li></ul><h2>In <span class="caps">NYC</span></h2>
<p>Just a note to myself, to remember some good places to work I found in <span class="caps">NYC</span>.
Might be useful for others :)</p>
<ul>
<li><a href="http://www.brooklynroasting.com/">Brooklyn Roasting Company</a> on Jay Street,
really cool place, good wifi, nice coffee and power outlets.</li>
<li><a href="https://www.facebook.com/pages/Black-Brick-Coffee/281642998540673">Black
brick</a> on
Bedford ave, really cool place, darker and smaller than <span class="caps">BRC</span>, but wifi and
power outlet as well.</li>
</ul>
<h2>In Berlin</h2>
<ul>
<li><a href="www.yelp.com/biz/homemade-berlin">Homemade</a></li>
</ul>Controlling servomotors on a Raspberry Pi2015-05-02T16:37:00+02:002015-05-02T16:37:00+02:00Phykstag:localhost,2015-05-02:/Blog/output/2015/05/controlling-servomotors-on-a-raspberry-pi.html<p>For a <a href="http://hackens.org/projets/disty">project</a> (documentation to be added soon) of low-cost telepresence robot, I had to handle three servomotors with a Raspberry Pi. I chose a Raspberry Pi board as it is very cheap and has a decent camera which can be easily used to stream video at a good resolution …</p><p>For a <a href="http://hackens.org/projets/disty">project</a> (documentation to be added soon) of low-cost telepresence robot, I had to handle three servomotors with a Raspberry Pi. I chose a Raspberry Pi board as it is very cheap and has a decent camera which can be easily used to stream video at a good resolution and framerate, without using too much <span class="caps">CPU</span>. Then, I wanted to control everything with the Raspberry Pi, including the servomotors. Here comes the troubles…</p>
<p>First of all, I had to control three servomotors: two continuous rotation servos for the wheels, and an extra standard servo for the camera orientation. First revisions of the RaspberryPi only have one hard <span class="caps">PWM</span>, shared with the audio circuit, which makes it really difficult to use for this purpose. But Raspberry Pi 2 has two hardware PWMs (one is shared with the audio circuit, preventing you from using the onboard audio output). That is enough for my use case, as I have two continuous rotation servos which have to be precise (and will be controlled via hard <span class="caps">PWM</span>) and an extra servo for the camera orientation which can be easily controlled in soft <span class="caps">PWM</span>.</p>
<p>My code can be found <a href="https://git.eleves.ens.fr/hackens/Disty/">here</a>. The important files are <a href="https://git.eleves.ens.fr/hackens/Disty/blob/master/headers/Servo.hpp">the header of Servo class</a>, <a href="https://git.eleves.ens.fr/hackens/Disty/blob/master/src/Servo.cpp">the actual Servo class</a> and <a href="https://git.eleves.ens.fr/hackens/Disty/blob/master/headers/constants.hpp">a file containing some extra constants</a>.</p>
<h2>Hard <span class="caps">PWM</span></h2>
<p>Next problem is to find a way to control them easily. On an Arduino, you just have to include the Servo library and write angles to your servos. On the Raspberry Pi, on the contrary, there are no such things. <a href="https://projects.drogon.net/raspberry-pi/wiringpi://projects.drogon.net/raspberry-pi/wiringpi/">WiringPi</a> is a nice C library to handle GPIOs (including <span class="caps">PWM</span>) but there are no default failsafe settings to use, and one has to play a lot with the different configuration commands.</p>
<p>Most of the servos expect pulses of variable width, sent on a 20ms basis. Each 20ms, it samples the wave to get the width of the pulse. The base <span class="caps">PWM</span> frequency on the Raspberry Pi is 19.2MHz, and you can set a clock prescaler (clock) and a number of samples (range). The base frequency of your <span class="caps">PWM</span> signal will then be given by the formula (as 50Hz = 20ms):</p>
<blockquote>
<p>19.2MHz / (clock * range) = 50Hz</p>
</blockquote>
<p>The stop position is for 1.5ms pulses in general, for a continuous rotation servo. Then, we also want that there exists a valid int such that we could write it to stop the servo. <code>pwmWrite(pin, STOP_VALUE)</code> should stop the servo, with <code>STOP_VALUE</code> being an int. This is important as servos are symmetric with respect to this position and a slight offset will make the calibration of the servo speeds really difficult.</p>
<p>Good results were obtained on my robot with a clock prescaler of 200 and a range of 1920. Then, the stop value was 141 and the full forward value was 155 (value to write to make the servo turn at full speed). This gives me 14 different speeds for the servo, which is more than enough in my case. If you want finer control, you should play with the clock prescaler and range values.</p>
<h2>Soft <span class="caps">PWM</span></h2>
<p>Then comes the control of the camera orientation using Software <span class="caps">PWM</span>. I explored two possibilities: <a href="https://github.com/richardghirst/PiBits/tree/master/ServoBlaster">ServoBlaster</a> which is not compatible out of the box with the Raspberry Pi 2 (but a <a href="https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=99115&start=25">solution</a> exists) and the software <span class="caps">PWM</span> library from wiringPi. Both gives equivalent results, including jitter (a bit less jitter for ServoBlaster, but still too much for a stable camera orientation). Then, I used wiringPi which was easier to integrate in my code. I found a dirty hack to fix servo jitter, as explained below.</p>
<p>First, the base frequency of the software <span class="caps">PWM</span> is 100Hz, but we need 50Hz for the servo control. Then, we have to <code>softPwmCreate</code> with a range of 200. We can then write values to the softPwm, and it will most likely work, at least if there are not much processes running.</p>
<p>My problem was that once I started the camera capture, my software pwm got preempted a lot, and this was giving a lot of jitter. This was really funny because when I was using autocompletion in the shell for instance, my servo had some jitter that I could hear. I tried to play with <code>nice</code> without success and could not get rid of the jitter.</p>
<p>However, I finally found a really hacky way of getting rid of the jitter (may not be applicable in your case): if I stop sending <span class="caps">PWM</span> signal to the servo, it holds still. Plus, if I send a 0 value on the <span class="caps">PWM</span>, this is an out-of-range value for the servo and he just ignores it, holding still as well. Then, the solution was easy. I just had to send the soft <span class="caps">PWM</span> signal to the servo, wait a bit until he has moved (based on the average speed in the datasheet, I know how long I have to wait) and then send 0 on the software <span class="caps">PWM</span>. This way, the servo holds still, and there is no more jittering.</p>
<p>Hope this helps :)</p>Blocking JavaScript on a per API basis2015-04-14T23:11:00+02:002015-04-14T23:11:00+02:00Phykstag:localhost,2015-04-14:/Blog/output/2015/04/blocking-javascript-on-a-per-api-basis.html<p>JavaScript is widely used on the Internet, and living without it can be a real pain. However, JavaScript use raises some security concerns, in particular because some JavaScript APIs can be really sensitive. Indeed, WebRTC calls can be used to <a href="https://diafygi.github.io/webrtc-ips/">detect your real <span class="caps">IP</span></a> even the private one, on your …</p><p>JavaScript is widely used on the Internet, and living without it can be a real pain. However, JavaScript use raises some security concerns, in particular because some JavaScript APIs can be really sensitive. Indeed, WebRTC calls can be used to <a href="https://diafygi.github.io/webrtc-ips/">detect your real <span class="caps">IP</span></a> even the private one, on your network, JavaScript can interact with the <a href="http://www.w3.org/TR/clipboard-apis/">clipboard</a>, … Clipboard <span class="caps">API</span> can be blocked in <code>about:config</code> in Firefox for instance, but that is not the case for every such <span class="caps">API</span>. Hence, I wanted to have a look at what can be done to prevent the use of such sensitive APIs.</p>
<p>Plus, in my opinion, <a href="https://noscript.net/">NoScript</a> is not really usable, as it blocks way too much things and you end up clicking on “Allow this website” on basically every website to be able to use them. Then, the security benefit from using NoScript gets very low.</p>
<p>I found a way (most a PoC than a real usable thing) to selectively block some APIs, through NoScript surrogate scripts and <code>Object.defineProperty</code>. For instance, to block the WebRTC PoC previously linked, one can add</p>
<div class="highlight"><pre><span></span><code><span class="nx">noscript</span><span class="p">.</span><span class="nx">surrogate</span><span class="p">.</span><span class="nx">test</span><span class="p">.</span><span class="nx">replacement</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">Object</span><span class="p">.</span><span class="nx">defineProperty</span><span class="p">(</span><span class="nb">window</span><span class="p">,</span><span class="w"> </span><span class="s1">'mozRTCPeerConnection'</span><span class="p">,</span><span class="w"> </span><span class="p">{</span><span class="nx">get</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">'rtc'</span><span class="p">);</span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{};</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nx">set</span><span class="o">:</span><span class="w"> </span><span class="kd">function</span><span class="p">()</span><span class="w"> </span><span class="p">{}});</span>
<span class="nx">noscript</span><span class="p">.</span><span class="nx">surrogate</span><span class="p">.</span><span class="nx">test</span><span class="p">.</span><span class="nx">sources</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="err">@</span><span class="o">^</span><span class="p">(</span><span class="o">?!</span><span class="nx">chrome</span><span class="o">:</span><span class="p">)[</span><span class="mf">0</span><span class="o">-</span><span class="mf">9</span><span class="nx">A</span><span class="o">-</span><span class="nx">Za</span><span class="o">-</span><span class="nx">z</span><span class="o">-</span><span class="p">]</span><span class="o">+</span>
</code></pre></div>
<p>in his about:config.</p>
<p>The <code>Object.defineProperty</code> syntax is a bit weird in this case, as I have to return a function in both the getter and the setter. I did not find any specific reason for doing it, and this is the only way I found to block this property. If you have any idea, please let me know, as I do not like to not understand this problem, and do not like much having something that could potentially break at any time. For the full discussion about this NoScript surrogate script, please refer to the <a href="https://forums.informaction.com/viewtopic.php?f=10&t=20666&sid=c38de78c3e5823ccc7bd931a8120fd2c">NoScript forum</a>.</p>
<p>Next steps would be to implement it as a standalone plugin, in order not to use NoScript and have a more user-friendly user interface (list all the sensitive APIs, one-click to enable / disable them and reload the page…), or better implement it as a <a href="http://www.privoxy.org/">Privoxy</a> <a href="http://www.privoxy.org/user-manual/filter-file.html#EXTERNAL-FILTER-SYNTAX">external filter</a> so that this protection will not be in the browser itself, but in a different layer, to increase security. I will work on it as soon as I find some free time, but feel free to do something and share in the mean time if you are interested in the topic!</p>Devops tools for workstations2015-04-06T23:08:00+02:002015-04-06T23:08:00+02:00Phykstag:localhost,2015-04-06:/Blog/output/2015/04/devops-tools-for-workstations.html<p>There is a growing interest in devops tools, such as Docker, Puppet / Ansible / Puppet / Chef to set up continuous integration, have the same working environment during development, testing, staging and production, and to manage thousands of servers in the cloud. However, I recently thought that some of these technologies could …</p><p>There is a growing interest in devops tools, such as Docker, Puppet / Ansible / Puppet / Chef to set up continuous integration, have the same working environment during development, testing, staging and production, and to manage thousands of servers in the cloud. However, I recently thought that some of these technologies could have a real interest as well for a few machines, for personal workstations. These are just some scenarios and use cases that happened to me, I did not test all of them and they may be irrelevant, feel free to let me know :)</p>
<h2>Scenario 1: I want a particular dev environment, without breaking everything</h2>
<p>First scenario is the most widely discussed around the web: I want my dev environment to be identical to production, but I do not want to break my system (python 2 vs 3, ruby stuff, …). For this purpose, one can use containers (e.g. <a href="https://www.docker.com/">Docker</a>). I will not elaborate much on this one.</p>
<p><em>Note</em>: I recently discovered that systemd had similar features through <a href="http://0pointer.de/blog/projects/changing-roots.html">systemd-nspawn</a>. In particular, see the <a href="http://0pointer.de/blog/">articles on Systemd</a> from Lennart Poettering to know more about this and systemd features.</p>
<h2>Scenario 2: I use many different operating systems</h2>
<p><em>Note</em>: I did not tried this scenario.</p>
<p>If you use many different operating systems on the same machine (say Windows and Linux for instance), then why not considering using virtualization? And not some palliative stuff like Virtualbox, but real hypervisors such as <span class="caps">KVM</span> or Xen. These are widely used on servers to run multiple VMs, but why not using them at home, on your personal computer?</p>
<p>CPUs today have a lot of virtualization-specific technologies, even on your workstation, and they are powerful enough to handle it. You will benefit from many advantages, starting from easy maintenance of your system (as it is just a <span class="caps">VM</span>, it is easier to backup / restore, isolate etc) and things like hot-switching between operating systems.</p>
<p>One problem may be left: handling the graphics card, which may not be easily shared by multiple VMs.</p>
<h2>Scenario 3: You want easy backup mechanism</h2>
<p>On important point I <a href="http://localhost/Blog/output/2015/03/you-are-not-selfhosting.html">previously discussed</a> is the ability to recover from any problem, hardware fault for example. It is important on a server, as downtime is a real problem, especially if you have few servers, but it is also a major concern on workstation. Especially as your laptop may fail at anytime: it can experience basic hardware failure, it may fall and break, it may be stolen…</p>
<p>Then, it is important to be able to recover a fully working system fast. One often talk about data backup, and this is indeed the most important as you cannot recover lost data contrary to a lost configuration (set of packages, state of configuration files, …). But this is not all. Reinstalling a system is a time-consuming task, and it is not really interesting.</p>
<p>Devops have came up with tools to deploy a given configuration on many servers, across the cloud. Those are Ansible, Puppet, Chef, Salt and so on. So, why not using them to deploy your computer configuration? If correctly managed, installing your laptop could be as easy as: partitioning the drive, bootstrapping the system (install base packages and set up an <span class="caps">SSH</span> access) and running Ansible (which is the most basic and fitted to this particular need) to reinstall everything else. Almost everything would be done automatically, perfect!</p>
<p>However, this requires to maintain a list of installed packages and associated files for Ansible to use, which can be a bit heavy on the run. Then, it could be interesting to have some way to ”blueprint” your system, to generate configuration descriptions from your existing system (as it is easier to install stuff on your system, tweak it and blueprint it after, than it is to do it tweaking Ansible configuration description and running it each time).</p>
<p>To achieve easy blueprinting, another solution is to use <a href="https://github.com/joeyh/etckeeper">etckeeper</a> to store all your files under /etc (as these are the only supposed to be modified by you, as /usr is the domain of your distribution and should not be modified) in a Git repository and keep a track of every changes in them. Restoring from etckeeper and list of installed packages (obtained with pacman) is quite easy and can even be done without Ansible.</p>
<p>On this particular subject of blueprinting, I wrote some Python script for Arch Linux (basically just a wrapper around good pacman commands), available <a href="https://git.phyks.me/Phyks/Blueprinting">here</a>. It may not be perfect, but will give you a basis to blueprint your system.</p>
<h2>Scenario 4: Sync multiple computers</h2>
<p>One last scenario is the following: I have three computers on which I work on an almost daily basis (my laptop, my desktop and another computer). Syncing files between them is quite easy (or at least achievable), but syncing configurations between them is much more difficult. In particular as the <em>whole</em> configuration should not be synced, as there is some device-specific configuration (fstab, <span class="caps">LVM</span> configuration, <span class="caps">SSH</span> host keys and stuff like that). But this problem is exactly the same as syncing multiple servers in the cloud, and is handled very well by Ansible. Plus Ansible let you define task and replicate only some of them on some machines and so on. Then, it is quite easy to synchronize completely multple computers to have the same work environment on all of them.</p>Quick comparisons of solutions for 3D cross-platform (mobile) development2015-03-27T22:00:00+01:002015-03-27T22:00:00+01:00Phykstag:localhost,2015-03-27:/Blog/output/2015/03/quick-comparisons-of-solutions-for-3d-cross-platform-mobile-development.html<p>I spent some time lately comparing available development toolkits for 3D games / apps on mobile platforms (mostly for hobby / indy apps). I do not want to have to adapt to much my base code depending on the target platform, and was then looking at a toolkit to write most of …</p><p>I spent some time lately comparing available development toolkits for 3D games / apps on mobile platforms (mostly for hobby / indy apps). I do not want to have to adapt to much my base code depending on the target platform, and was then looking at a toolkit to write most of the code once, and be able to build the app for various platforms on the market. My use case is:
* sufficient 3D engine (not necessarily a high end thing, just the basics to be able to write 3D apps decently. I consider <a href="http://threejs.org/">Three.js</a> as sufficient for my needs for instance).
* I am working on Linux, so the ability to dev on Linux would be a real plus.
* of course, it should be as less expensive as possible :)
* and finally, I am paying much attention at the <span class="caps">EULA</span> and licenses, as I do not want to force my users to send “anonymous” statistics, I do not want my app to need extra (and useless) permissions and so on.</p>
<p><em>Note</em>: I did <em>not</em> test these toolkits deeply, and am just reporting here what I found while playing a bit with them and comparing the features, licenses and requirements. I only included</p>
<h2><a href="https://cordova.apache.org/">Cordova</a></h2>
<p>First toolkit I had a look at was Cordova. It allows you to write pure web apps (using standard <span class="caps">HTML</span> / <span class="caps">CSS</span> / <span class="caps">JS</span> and providing some extra APIs to extend the available APIs, for bluetooth for instance) and to package them into native apps distributed through the market. What it does is basically add a wrapper around your web app to render it outside a browser, using the offered web abilities provided by webviews on iOs and on Android. Writing a web app is really super easy, and then having a first working prototype using Cordova is super fast. Cordova runs on Linux without any problems.</p>
<p>It works pretty well for 2D graphics and basic applications (but needs some extra permissions as it uses a web view, even if it is not communicating over internet). But when it comes to 3D graphics, using WebGL, you will be in troubles. Indeed, the webview in Android 4.x is using an old version of Chrome, even if you install the latest Chrome on your mobile. Then, you will not be able to use WebGL as it is simply not supported, unless you use some hack to actually use a more recent Chrome version, using <a href="https://crosswalk-project.org/">Crosswalk</a> for instance. On iOS, this is even worse as WebViews prior to iOS8 do not support WebGL (and as far as I know, there is no alternative which will be both stable, reliable and will go through the reviewing process of the appstore). This mean that you will not be able to target iPhones prior to (and including) iPhone 4, and iPad 1, which in my opinion is a real problem.</p>
<h2><a href="https://www.unrealengine.com/">Unreal Engine</a></h2>
<p>Second option is to use the Unreal Engine 4. It is a complete 3D game engine, including many tools to build 3D apps that you can deploy on many platforms (both desktop, web and mobile). You can code in C++ with it, and script using many visual tools. It includes dedicated APIs for advanced features such as Virtual Reality (<span class="caps">VR</span>) and may sound overkill.</p>
<p>You can dev using Windows and Mac (officially supported), but not Linux (at least, not officially). However, it seems that the dev editor can be installed on Linux at the cost of a bit of hacking, and this should be even easier to install in the near future as there seems to be a Linux community.</p>
<p>Unreal Engine charges you with 5% royalties passed the first 3k$.</p>
<p>Here are some relevant <span class="caps">EULA</span> fragments:</p>
<blockquote>
<ol>
<li>Hardware and Usage Data</li>
</ol>
<p>You acknowledge that, as a default setting, the Engine Code will collect and send to Epic anonymous hardware and usage data from end users of Products. This functionality is used by Epic to improve the Engine Code. You may modify the Engine Code under the License to turn off that functionality in your Product, or you may include in your Product the capability for your end users to turn off that functionality in the Product.</p>
</blockquote>
<p>and</p>
<blockquote>
<p>You agree to keep accurate books and records related to your development, manufacture, Distribution, and sale of Products and related revenue. Epic may conduct reasonable audits of those books and records. Audits will be conducted during business hours on reasonable prior notice to you. Epic will bear the costs of audits unless the results show a shortfall in payments in excess of 5% during the period audited, in which case you will be responsible for the cost of the audit.</p>
</blockquote>
<p>The second one is a standard one, as you have to pay royalties depending on your revenues. But the first one is really concerning, as by default Unreal Engine will track your users and send anonymous statistics (thus requiring extra and unneeded permissions and raising privacy concerns). However, once you are aware of it, you can freely modify your app to prevent this, according to the <span class="caps">EULA</span>, so this is not a big deal in the end.</p>
<h2><a href="http://unity3d.com/">Unity</a></h2>
<p>Latest solution I found (used by <a href="http://www.monumentvalleygame.com/">Monument Valley</a> for instance) is the Unity game engine. The personal license is sufficient in most of the cases, and is free to use up to 100k$ gross revenue. The dev tools are available on Windows and Mac, but there is no Linux version (and no hacky way to get it in Linux).</p>
<p>Here are some relevant fragments from <span class="caps">EULA</span> as well:</p>
<blockquote>
<p>(c) users will be required to complete a user survey to activate the Software. Unity Pro users who are not eligible to use Unity Personal may not develop and publish Licensee Content for the iOS and Android platforms without purchasing the applicable Unity Pro Add-On Product license. Unity may monitor your compliance with and enforce these restrictions and requirements including but not limited to monitoring the number of downloads of your Licensee Content and any available revenue estimate data.</p>
</blockquote>
<p>This one is not really clear, and I am not really sure of what it really implies. However, according to <a href="http://unity3d.com/legal/eula">http://unity3d.com/legal/eula</a> and <a href="https://unity3d.com/legal/privacy-policy">https://unity3d.com/legal/privacy-policy</a>, it seems to imply that statistics are sent and that you cannot avoid it, even in the pro version.</p>
<blockquote>
<p>We also include certain device data collection in the runtime of the Software which is incorporated into the applications you create with the software. You should be sure that your privacy policy explains to your players the variety of technical information that is collected and shared with third parties like Unity.</p>
</blockquote>
<p>and</p>
<blockquote>
<p>Q: I play a game built with Unity software, what should I know?</p>
<p>A: Unity has probably collected some or all of the following information about your device: Unique device identifier generated from the device <span class="caps">MAC</span>/<span class="caps">IMEI</span>/<span class="caps">MEID</span> (which we immediately convert into a different number using a one way hash); <span class="caps">IP</span> address; Device manufacturer and model; the operating system and version running on your system or device; browser type; language; the make of the <span class="caps">CPU</span>, and number of CPUs present; the graphics card type and vendor name; graphics card driver name and version (example: “nv4disp.dll 6.10.93.71”); which graphics <span class="caps">API</span> is in use (example: “OpenGL 2.1” or “Direct3D 9.0c”); amount of system and video <span class="caps">RAM</span> present; current screen resolution; version of the Unity Player; version of the Unity Editor used to create the content; a number describing whether the player is running on Mac, Windows or other platforms; and a checksum of all the data that gets sent to verify that it did transmit correctly; application or bundle identification (“app id”) of the game installed. Some Unity developers use Unity’s analytics and ad services which collect additional information. See FAQs on Unity Analytics and Unity Ads below.</p>
<p>Q: That seems like a lot of data, why so much?</p>
<p>A: We try to limit the collection of this information from any one player or device; however, certain operating systems do not permit us to note that the info has already been collected. This means that the data may be sent to Unity each time you start the game. We use the information to make decisions about which platforms, operating systems and versions of them should be supported by our game development software. We aggregate this data and make it available to developers at stats.unity3d.com. This data helps us improve our Services and helps developers improve their apps.</p>
<ol>
<li>
<p>Your choices about Unity’s collection and use of your information</p>
<p>You always have the option to refrain from using the Service or to discontinue using the Service if you do not want information collected about you.</p>
</li>
</ol>
</blockquote>
<p>They also explictly says in the <span class="caps">FAQ</span> that there is no opt-out, and the anonymous stats are indeed browsable at <a href="http://stats.unity3d.com/mobile/">http://stats.unity3d.com/mobile/</a>. In conclusion, contrary to Unreal Engine, I do not think you can easily prevent the engine from sending anonymous statistics, which is a pity in my opinion. Moreover, there are a number of threads talking about extra permissions required by Unity (such as network access to send the statistics) and there seems to be no way to not require those permissions and to still conform to the <span class="caps">EULA</span>: <a href="http://answers.unity3d.com/questions/663197/how-to-prevent-unity-from-adding-permissions-to-an.html">http://answers.unity3d.com/questions/663197/how-to-prevent-unity-from-adding-permissions-to-an.html</a> and <a href="http://forum.unity3d.com/threads/extra-permission-needed-in-android.295556">http://forum.unity3d.com/threads/extra-permission-needed-in-android.295556</a>.</p>“You are not selfhosting”…2015-03-26T17:05:00+01:002015-03-26T17:05:00+01:00Phykstag:localhost,2015-03-26:/Blog/output/2015/03/you-are-not-selfhosting.html<p>“You are not selfhosting”… that is more or less what Laurent Guerby (founder of <a href="http://tetaneutral.net/">Tetaneutral.net</a> told me last week after a presentation <a href="http://socialismecapitalismedeuxpointzero.net/">at the <span class="caps">ENS</span></a>). At first, it surprised me, because I <strong>am</strong> selfhosting. I have my own server to serve this blog, to handle my emails, to connect …</p><p>“You are not selfhosting”… that is more or less what Laurent Guerby (founder of <a href="http://tetaneutral.net/">Tetaneutral.net</a> told me last week after a presentation <a href="http://socialismecapitalismedeuxpointzero.net/">at the <span class="caps">ENS</span></a>). At first, it surprised me, because I <strong>am</strong> selfhosting. I have my own server to serve this blog, to handle my emails, to connect to <span class="caps">IRC</span>, to handle my <span class="caps">XMPP</span> account, to provide me a fully working network access and so on. Basically every part of my life on internet passes somehow through my server, so I am tempted to consider that I <strong>do</strong> selfhost.</p>
<p>Plus I wrote <a href="http://phyks.me/autohebergement.html">some notes</a> (in French) about the checklist before selfhosting and the first step in selfhosting. What is the status of this document if indeed I am not selfhosting?</p>
<h2>“You need two machines to selfhost, not one”</h2>
<p>Actually, most people forget it when they talk about selfhosting, but to fully selfhost, you need <strong>2</strong> machines, and not only one. Indeed, if you use the cloud services from Google, Facebook, etc., your data are replicated across their datacenters. Your data are stored multiple times, in multiple places around the world and this limits the risk of data losses (both temporary, due to network issues, or permanently).</p>
<p>On the contrary, if you selfhost on a single server, your data is stored only at one place, on one machine. This means that any problem on this machine will kill your entire numerical life. Some people use two servers, but at the same place (a Synology and a Raspi at home for instance). In this case, you do have data replication and you can indeed recover from a material problem, but you will run into troubles if there is a physical problem, like a fire or a simple network failure.</p>
<p>Imagine you have <a href="https://en.wikipedia.org/wiki/MX_record#The_backup_MX"><span class="caps">MX</span> backup</a> on two machines on the same network access. If one of the server experiences problems, the other one will be able to handle emails delivery, but if the problem is on the network access, <span class="caps">MX</span> backup is useless.</p>
<p>Same thing happen if you have a fire at home and all your devices (backupped one plus the server to store the backups) are at home. You will simply lose everything.</p>
<p>Then, if you care about the service you benefit from, you should have two servers in distinct places. Else, you will not have the same quality of service as the one you would have with the standard cloud, and selfhosting is not that much interesting and not worth the price. Note that you do not need to actually <strong>own</strong> two machines: you can also use a part of a friend’s server, as discussed below.</p>
<p>On this part, I am backupping my server daily on a friend server (encrypted backups, so no privacy concerns to have), and we set up some redundancy as <span class="caps">MX</span> backups and so. Then, I have effectively two machines, so that my downtime is reduced, and I can mitigate problems with my main server.</p>
<h2>“You need to be able to move quickly”</h2>
<p>Another problem, often neglected (starting from my own notes) is the ability to move quickly to another place, and to fully disappear (so that noone can recover anything from your server). This, of course, depends on your hosting-provider, and if you have a one year contract with your hosting-provider, it might not be that easy (or cheap at least) to move to another server, in the end.</p>
<p>The point of being able to move quickly is:</p>
<ul>
<li>To be able to move if you have troubles with your hosting-provider, so that you are fully free and selfhosted and not tied to your hosting-provider.</li>
<li>To be able to setup a new server very quickly in case of problems (electrical failure, network problem, hard-drive failure, …), to reduce downtime.</li>
</ul>
<p>Reconfiguring a server is a time-consuming task, and is a real pain, so you will want to do it as less as possible, and will hence increase the dependency on your hosting-provider.</p>
<p>People handling thousands of servers in the cloud use tools like <a href="https://puppetlabs.com/">Puppet</a>, <a href="http://www.ansible.com/home">Ansible</a>, <a href="https://www.chef.io/chef://www.chef.io/chef/">Chef</a> or simple shell scripts to spawn new machines upon need and replicate their config across all their machines. Even if you have only one or two machines, you should consider using it as they are rather easy to use and not reserved to use with thousands of machines. It will ease configuration, it will allow you to version your configuration and to easily spawn a new server very quickly. Combined with data backup, you can virtually spawn a working new server in a few minutes, anywhere you want, anytime you want.</p>
<p>Another point to consider is also the ability to disappear quickly and prevent anyone from recovering your data, especially if you own a server provided by your hosting-provider. These are not necessarily wiped between two users, and the next one could potentially recover sensitive data from the hard drive (like emails). A simple solution (at the cost of a bit of computational power) to this is to encrypt your disk, and delete the sector storing the keys before returning the server. This way, your hard drive will just look like garbage to the next owner, and he will not be able to recover anything from it.</p>
<p>Moreover, here are some other thoughts which came to me while I was thinking in the previous points.</p>
<h2>Mutualization is not centralization</h2>
<p>Most of the time, when we speak about selfhosting, we speak about <em>self</em> which means all the debate is focused on the user. We often oppose selfhosting (decentralization) to centralization, and focus only on the setup of <strong>one</strong> server for <strong>one</strong> user. This can be well seen in projects like <a href="http://yunohost.org/">Yunohost</a> which allows any user to setup easily its own personal server on an old machine or a Raspberry Pi, but will not offer anything else.</p>
<p>However, mutualization is not centralization, and selfhosted users could benefit a lot from mutualization. Distributions like Yunohost should build a “network” of users, and offer them mutualization capabilities. For instance, one should be able to easily let 10% of his hard drive to be used for other users’ backups, and benefits from the ability to replicate its backups on others servers. This way, sharing a bit of storage, one can have a distributed backup storage, resilient to network failures and server issues. This is especially easy as we have technologies which allow us to do distributed and encrypted file storage across multiple servers, such as <a href="http://tahoe-lafs.org/">Tahoe-<span class="caps">LAFS</span></a>. But such solutions are not promoted at all by distributions like Yunohost…</p>
<p>Indeed, maintaining two servers is quite a pain, and might cost a lot, especially if one of them is just here for backups. On the contrary, you might know someone having a server and who is ready to exchange a bit of storage, bandwidth and <span class="caps">CPU</span> power to mirror your services and handle backups. This network of trusted users (or not necessarily, if you use encryption and distributed file storage) is a key element of selfhosting, in my opinion, and should be promoted and made easy.</p>
<h2>Trust in the server</h2>
<p>Last but not least, as soon as you rent a server to someone else, you need to trust him to give you the server he advertised, and to not abuse his power. If you pay a server, you might expect to have the server you ordered, or the hosting-provider will suffer from the secret if known. But what about the configuration he sets up for you? What about judiciary requests (or not so official requests)? Will he simply give the information, the access to your server in the datacenter etc easily, or will he warn you before? These are things that should be considered, with more or less care depending on why you want your server and the way you use it. But such concerns should not be avoided and should be taken into account (although it will most likely be better than with a cloud provider, in any case).</p>
<p>Possible mitigations for this point are to fully self-host your server (which means buying a server or recycle an old <span class="caps">PC</span>, host it at home, if your network connection is powerful enough, or rent a rack in a datacenter), but this can cost much more. Another solution is to look at associative hosting providers, such as <a href="http://tetaneutral.net/">Tetaneutral.net</a> which offers to host your server, no matter what its format is. As it is your machine, you know the material, and you can add the security level you want (such as killswitches and so on).</p>TupperVim du 03/03/20152015-03-14T00:36:00+01:002015-03-14T00:36:00+01:00Phykstag:localhost,2015-03-14:/Blog/output/2015/03/tuppervim-du-03032015.html<p>J’ai été à la <a href="http://tuppervim.org">TupperVim</a> le 3 mars dernier dans les locaux de mozilla à Paris. Voici quelques notes de trucs que j’ai appris et noté pour ne pas les perdre.</p>
<ol>
<li>^A (respectivement ^X) sert à incrémenter (respectivement décrémenter) le premier terme que Vim peut incrémenter (respectivement décrémenter …</li></ol><p>J’ai été à la <a href="http://tuppervim.org">TupperVim</a> le 3 mars dernier dans les locaux de mozilla à Paris. Voici quelques notes de trucs que j’ai appris et noté pour ne pas les perdre.</p>
<ol>
<li>^A (respectivement ^X) sert à incrémenter (respectivement décrémenter) le premier terme que Vim peut incrémenter (respectivement décrémenter) sur la ligne. Par exemple, sur la ligne</li>
</ol>
<div class="highlight"><pre><span></span><code>texte 1
</code></pre></div>
<p>faire ^A donne</p>
<div class="highlight"><pre><span></span><code>texte 2
</code></pre></div>
<ol>
<li>
<p>Utiliser <code>gj</code> pour se déplacer d’une ligne à l’écran. En particulier, si une ligne est trop longue et qu’elle se retrouve affichée sur plusieurs lignes à l’écran (<em>wrap</em>), utiliser <code>gj</code> permet de descendre d’une ligne, en restant dans la même ligne du fichier.</p>
</li>
<li>
<p><code>*</code> sur n’importe quel mot cherche la prochaine occurrence du même mot. On peut utiliser <code>n</code> et <code>N</code> après pour se déplacer entre les occurrences.</p>
</li>
<li>
<p><code>#</code> fait la même chose, en sens inverse.</p>
</li>
<li>
<p><code>:reg</code> liste les registres.</p>
</li>
<li>
<p><code>:buffers</code> liste les buffers.</p>
</li>
<li>
<p><code>y, :%s/^R"</code> permet de rechercher / remplacer le texte sélectionné comme le propose bon nombre d’éditeurs graphiques.</p>
</li>
<li>
<p><code>^i</code> et <code>^o</code> permettent de parcourir le fichier dans l’ordre antichronologique des derniers sauts.</p>
</li>
<li>
<p><code>g,g;</code> permet de faire de même en parcourant par modifications en ordre antichronologique.</p>
</li>
<li>
<p><code>:jump</code> permet de lister les précédents sauts.</p>
</li>
<li>
<p><code>:changes</code> permet de lister les dernières modifications.</p>
</li>
<li>
<p><code>^o</code> enmode insertion permet d’échapper la prochaine commande pour qu’elle soit exécutée comme si on était en mode normal.</p>
</li>
<li>
<p><code>set list listchars=nbsp:¤,tab:··,trail:¤,extends:▶,precedes:◀</code> permet d’afficher des caractères spéciaux (unicode) pour les espaces insécables, les tabulations, les espaces de fin de ligne et les lignes qui dépassent de l’écran.</p>
</li>
<li>
<p><code>command! W w !sudo tee "%" > /dev/null</code> permet d’enregistrer en tant que root un fichier ouvert avec un Vim lancé en utilisateur standard. À noter qu’il existe aussi <code>sudoedit</code> pour éditer un fichier en utilisant <code>sudo</code> intelligemment, pour éviter de permettre l’exécution de commandes en root par le vim ouvert.</p>
</li>
<li>
<p>La grammaire de vim est super top ! On choisit un verbe (<code>c</code> pour “change” par exemple). On choisit un modificateur (<code>i</code> pour “inner” pour modifier dans le sélecteur courant, <code>a</code> pour “around” pour modifier autour du sélecteur courant) et un sélecteur, comme <code>(</code> pour supprimer le contenu entre les parenthèses délimitantes. D’autres sélecteurs sympas sont <code>p</code> pour le paragraphe actuel, <code>B</code> pour le bloc actuel (entre accolades en C par exemple) ou <code>t</code> pour le tag courant en <span class="caps">HTML</span>. Ainsi, <code>dap</code> supprime tout le paragraphe courant</p>
</li>
</ol>Installing aNimble on Windows2015-02-28T16:11:00+01:002015-02-28T16:11:00+01:00Phykstag:localhost,2015-02-28:/Blog/output/2015/02/installing-animble-on-windows.html<p>Today, I had to install aNimble platform. As there are very few documentation available on the web about the installation of this software, here are some notes that could be useful to anyone interested in aNimble. Not of much interest for others, though =(</p>
<p><a href="http://sourceforge.net/projects/nimble/">aNimble Platform</a> is a requirements management tool …</p><p>Today, I had to install aNimble platform. As there are very few documentation available on the web about the installation of this software, here are some notes that could be useful to anyone interested in aNimble. Not of much interest for others, though =(</p>
<p><a href="http://sourceforge.net/projects/nimble/">aNimble Platform</a> is a requirements management tool designed to achieve full <span class="caps">SDLC</span> traceability for features, requirements, design, implementation and testing. It is the new version of <span class="caps">OSRMT</span>.</p>
<p>However, all the existing docs on the web are no longer available. Here is a small how to to install it and make it run on a Windows <span class="caps">PC</span>.</p>
<p>First of all, it uses Java and the Grails and Spring Framework. It uses Grails version 2.1.1, provided in the zip archive. Grails version 2.1.1 is not compatible with Java <span class="caps">JDK</span> 8 and aNimble is not running out of the box with Grails 2.4.4. Then, install the <a href="http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html">Java <span class="caps">JDK</span> 7</a> and set your <code>JAVA_HOME</code> environment variable to the install directory of the <span class="caps">JAVA</span> <span class="caps">JDK</span>.</p>
<p>aNimble requires a MySQL server for data storage. For example, download [the latest version] (http://dev.mysql.com/downloads/mysql/) and starts <code>MYSQL_PATH/bin/mysqld.exe</code>.</p>
<p>Then, create the database:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>MYSQL_PATH/bin/mysql.exe
<span class="go">> CREATE DATABASE aNimble_platform;</span>
<span class="go">> quit;</span>
</code></pre></div>
<p>Go to the directory containing the aNimble app (<code>animble_platform_v0_4/nimble_grails</code>) and update the MySQL credentials in <code>grails-app/conf/DataSource.groovy</code> (lines 32 and 33, if MySQL is ran from <code>mysqld.exe</code> without specific config, username is “root” and password is empty (“”)). You can then initialize the database with <code>grails prod execute-database-scripts-all</code>.</p>
<p>You can then start the server to serve the aNimble app, either in production or dev mode, using <code>start_prod_anp.bat</code> or <code>start_dev_anp.bat</code>. aNimble should be accessible at <span class="caps">URL</span> <code>http://localhost:8080/animble_platform/</code>.</p>
<p>Default admin account is:
Username: <span class="caps">DEMO</span>
Password: nimble</p>Looking for altitude OpenData2015-02-13T17:35:00+01:002015-02-13T17:35:00+01:00Phykstag:localhost,2015-02-13:/Blog/output/2015/02/looking-for-altitude-opendata.html<p>Recently, for a personal project, I looked for opendata for altitude in France. These are not so easy to find, although there are some really good opendata out there, with a very great accuracy. Indeed, <a href="http://www.openstreetmap.org/#map=5/51.500/-0.100">OpenStreetMaps</a> provides really accurate opendata for maps (street names and so on), but absolutely nothing …</p><p>Recently, for a personal project, I looked for opendata for altitude in France. These are not so easy to find, although there are some really good opendata out there, with a very great accuracy. Indeed, <a href="http://www.openstreetmap.org/#map=5/51.500/-0.100">OpenStreetMaps</a> provides really accurate opendata for maps (street names and so on), but absolutely nothing concerning the altitude.</p>
<p>I finally found two datasets available for France, one published by <a href="https://www.data.gouv.fr/fr/datasets/bd-alti-75m/"><span class="caps">IGN</span></a> and the other one being the <a href="http://wiki.openstreetmap.org/wiki/SRTM"><span class="caps">SRTM</span></a> dataset published by the <span class="caps">NASA</span>. The one from <span class="caps">IGN</span> provides altitude information for the whole French territory, at a resolution of 75m, which is quite good for numerically modeling the terrain. The one from <span class="caps">NASA</span> is more complete and provides altitude information for the whole globe surface between -60° and 60° latitude at a resolution of about 90m, obtained by averaging on 30m samples.</p>
<h2><span class="caps">IGN</span> <span class="caps">BD</span> <span class="caps">ALTI</span> opendata</h2>
<p>First of all, let’s have a look at the <span class="caps">BD</span> <span class="caps">ALTI</span> from <span class="caps">IGN</span>, which is not as widely used as the <span class="caps">SRTM</span> one (at least in a hobbyist context) and does not have much documentation around there.</p>
<p><span class="caps">IGN</span> provides an archive containing the data for the whole French territory. In the archive, there are several folders. The interesting one, in our case, is <code>1_DONNEES_LIVRAISON_*</code> which contains all the data files.</p>
<p>Altitude data is available in two formats: GeoTiff (Tiff with geolocation metadata) and <span class="caps">ASCII</span> Esri grid. I personally used the <span class="caps">ASCII</span> Esri Grid files. For more info about this file format, you can refer to <a href="https://en.wikipedia.org/wiki/Esri_grid#ASCII">the Wikipedia page</a>.</p>
<p>Each file starts with some header informations: number of rows and cols (1000), position of the lower-left corner in X and Y coordinates, size of an elementary cell and value used to indicate missing data. The file then contains a matrix representing the values of each cell, as described in the Wikipedia page.</p>
<p>Position on the map is indicated in X and Y coordinates, and not using the standard latitude and longitude coordinates. This is a different projection system, called <a href="https://fr.wikipedia.org/wiki/Projection_conique_conforme_de_Lambert">Lambert93</a>, and used for official maps of France. <a href="https://fr.wikipedia.org/wiki/Projection_conique_conforme_de_Lambert">Wikipedia</a> contains the relevant information to translate from the standard <span class="caps">WGS84</span> (satellite latitude and longitude coordinates) to the Lambert93 coordinates, and reciprocally but the best way seems to be to use the <a href="http://trac.osgeo.org/proj/">Proj.4 libray</a> which has a <a href="https://pypi.python.org/pypi/pyproj?">Python binding</a> to handle the conversion.</p>
<p>To find a specific point, you should then iterate over the available data files and check if the position of the point is between <code>xllcorner, yllcorner</code> and <code>xllcorner + ncols * cellsize, yllcorner + nrows * cellsize</code>. Then, you just have to get the value of the matching cell in the matrix description in the file.</p>
<p>An example script is available at <a href="https://github.com/Phyks/IGN_OpenData">https://github.com/Phyks/IGN_OpenData</a>. It takes a rectangle defined by two latitudes and longitudes in input, as well as the data folder to process, and will output the relevant data from the <span class="caps">BD</span> <span class="caps">ALTI</span> dataset, in <span class="caps">XYZ</span> file format, which is equivalent to a <span class="caps">CSV</span> file with columns X, Y and altitude (Z), separated by tabulations, and sorted. This is also an example use of the Proj.4 Python binding to handle basic coordinates system transforms.</p>
<h2><span class="caps">SRTM</span> opendata</h2>
<p>The <span class="caps">SRTM</span> dataset exists in multiple versions and different samplings. Have a look at <a href="https://github.com/Phyks/IGN_OpenData">this wiki page</a> to have more information about it. I was interested in <span class="caps">SRTMGL3</span> version 3, which is the third iteration of the dataset sampled at 3 arcseconds (which is about 90m). It is available at <a href="this address">http://e4ftl01.cr.usgs.gov/<span class="caps">SRTM</span>/<span class="caps">SRTMGL3</span>.003/</a> (before clicking the main folder in this address, please note that this is very heavy and long to process as it contains all the files for the whole world). <a href="https://linuxfr.org/users/jben/journaux/rv-herve-recherche-d-itineraire-velo-minimisant-l-energie-en-utilisant-les-donnees-d-osm">rv</a> uses it and provides a basic import script to a PostgreSQL database, available <a href="https://gitlab.crans.org/leger/rv/blob/master/height/populate_height_table.cc">here</a>.</p>
<p>All files are named with a convention to describe the tile they represent. For instance, the tile starting at 0° North and 6° East is called <code>N00E006.*</code>.</p>
<p>There is a really nice <a href="https://gis.stackexchange.com/questions/43743/how-to-extract-elevation-from-hgt-file">StackOverflow post</a> to explain how to handle these files and the following will almost be a rewriting of this post.</p>
<p>First of all, take the integer part of the position you want (latitude and longitude), and look for the corresponding file at the previous address. You will download a (zipped) hgt file containing the altitude data. This file is a big-endian binary file that you will have to parse.</p>
<p>First, you have to find the pixels coordinates representing your geographic point. To this purpose, you have to take the floating part of the latitude and longitude of the point you want and convert them to arcseconds (e.g. for 50° 24’ 58.888”, you will have 24 * 60 + 58.888 = 1498.888). As the sampling is done at 3 arcseconds, the pixel coordinates are given by the closest integer to the latitude (resp. longitude) of your point, expressed in arcseconds, divided by 3. Latitude will give you the row index, whereas longitude will give you the col index.</p>
<p>The first row in the file is the northernmost one, so if we are looking at row 500 from the lower edge, we actually have to look at row 1201 - 500 from the beginning of the files (1200 being 3600 / 3, the total number of rows in the data file).</p>
<p>We then have to iterate on cols to find the correct one, using the same principle.</p>
<p>An example script is available <a href="https://github.com/Phyks/IGN_OpenData/blob/master/srtm_alti.py">here</a> although it was not thoroughly tested. If you fix any problem with it, please report :)</p>Definitely moving to Known2015-01-22T21:53:00+01:002015-01-22T21:53:00+01:00Phykstag:localhost,2015-01-22:/Blog/output/2015/01/definitely-moving-to-known.html<p>As announced in <a href="https://known.phyks.me/2015/thoughts-on-blogging-engine">a previous
article</a>, I
definitely moved to Known. The new <span class="caps">RSS</span> feed is available at
<a href="https://phyks.me/?_t=rss">https://phyks.me/?_t=rss</a>.</p>
<p>There might be some dead links due to the transition, but the content should
still be available at a different <span class="caps">URL</span> on this instance.</p>Why I am quitting Diaspora?2015-01-20T19:42:00+01:002015-01-20T19:42:00+01:00Phykstag:localhost,2015-01-20:/Blog/output/2015/01/why-i-am-quitting-diaspora.html<p>I tried Diaspora for the last six months or so. I was seeing it as a real
potential alternative to Facebook and other social networks. At the time, it
was one of the most advanced decentralized social networks I knew about, and
there were many people trying it, after some …</p><p>I tried Diaspora for the last six months or so. I was seeing it as a real
potential alternative to Facebook and other social networks. At the time, it
was one of the most advanced decentralized social networks I knew about, and
there were many people trying it, after some articles from <a href="http://cyrille-borne.com/">Cyrille
Borne</a>. I have never really been fond of social
networks, but was thinking this decentralized network could be fun, in
agreement with my ideas and also a good way for my hackerspace to communicate
with a geek public. I was not really convinced at first, but it was mostly due
to the fact that I am not a huge fan of social networking, and I wanted to
give it a try, hoping that it may develop further.</p>
<p>Finally, after 6 months of test, I think it is not worth maintaining yet
another software on my server, and I am definitely quitting Diaspora. Here is
some feedback…</p>
<h2>There is nobody…</h2>
<p>Yep, there is truly nobody. I knew some friends using it, in advance, and I
was not really alone. But there is not much people using it, and they are
mostly geeks and tech users. Moreover, there is no way to communicate easily
from Diaspora to other social networks (contrary to what the
<a href="http://indiewebcamp.com/">IndieWebCamp</a> is trying to do). This means you have
Facebook or whatever social network your friends use to communicate with them,
and Diaspora for your geek friends. That is not very practical at all.</p>
<p>Moreover, this also means that you won’t know much people on Diaspora in real
life. Then, the way you publish is not really one of a social network,
publishing stuff about yourself and your holidays and so on, so that your
friends may be aware. It is much more like Twitter or a blog, and, personally,
I prefer having a blog :)</p>
<p>Finally, last but not least, if you are running your own pod, as I was, you
should know that you will really be alone. Indeed, Diaspora is only
half-decentralized. The different pods (instances of Diaspora) can communicate
one with each other, but only in limited ways. They can share posts, likes,
reshares and so on, but there is no strict federation for everything. For
example, contacts list is not federated. This means that if you have your own
pod, you won’t be able to crawl your friends’ list to find new people to
follow. Even worse, the hashtags are not federated. This means that your pod
will show you things like streams for trendy hashtags, say #something, but it
will only show messages tagged with #something from your pod (either your
messages or messages from your friends and then your pod as a backup copy).
That’s not really interesting…</p>
<h2>The software is super ugly</h2>
<p>Well, the software is under heavy dev, but they are not moving really fast, or
at least it does not reflect in the user experience. Six months later, there
are still the same basic annoying bugs in the user interface : on posting, the
post form is reseted, even if the posting failed due to network loss (and then
it is just a pity to post things in a train or in the countryside), the
interface uses Bootstrap but lacks responsiveness and some menus are still
hidden due to poor <span class="caps">CSS</span> in mobile mode, …</p>
<p>To make people come from Facebook and not only have a geek public, they should
improve this user experience part, and focus on easy connectivity with other
such services (Google Plus, Facebook, Twitter, Instagram for instance). That
is what are doing people from the <a href="http://indiewebcamp.com/">IndieWebCamp</a>,
<a href="http://withknown.com/">Known</a> and <a href="http://brid.gy/">Bridgy</a>, and in fact,
after discussing with some non-tech friends, they are much more interested in
these softwares than in Diaspora.</p>
<p>Some must-have features are also still heavily discussed and not ready to be
implemented. Such things include a realtime chat, either based on <span class="caps">XMPP</span> or
WebRTC. People heavily use the Facebook chat, people discuss on Twitter, they
also want to discuss in Diaspora. The private messages are highly unpractical,
and there is no built-in chat, which is a real lack in my opinion.</p>
<p>To sum up, in the last six months, there have been a bunch of commits and new
versions, but nothing really new in the user interface. It might be either
that the backend software is way too complicated and requires too much
maintenance (which is then a real problem) or that they are not interested in
the user interface at all, but that’s really sad. It is even worse when you
have to use it to communicate with Diaspora, as we will see next (you do not
have any really usable alternative interface right now).</p>
<p>Another point is that Diaspora is built around Ruby on Rails, which is just a
real pity to install on your own server. If you have a shared host, you just
cannot run it. If you have your own server, you will have some fun installing
the right Ruby version on your Debian stable and installing everything… Docker
images can improve it a bit, but that is definitely not a software written in
a way to be widely spread and that each one runs his pod (as we saw with the
federation problem). This is a bit contrary to the marketed things… As it is
written in Ruby (contrary to most opensource and decentralized stuff like
<a href="http://wordpress.org/">Wordpress</a>), not much people can contribute. I
personally do not speak Ruby, and cannot modify the software much. This is
even more a problem when the community is assuming you know Ruby…</p>
<h2>It lacks a warm community</h2>
<p>Most of this reflexion was triggered when I discovered other attempts to
decentralize stuff. At least recent attempts to do so. They are not counting
on their users to move definitely to their software, or use it with a side
software to communicate with their friends, but try to offer an interface to
post data to all the networks and get backfeeds. Since
<a href="https://fr.wikipedia.org/wiki/StatusNet">Status.net</a>, everyone saw that the
old way is not working and now try to build stuff interacting with the rest of
the ecosystem, using standard protocols whenever possible and APIs if no other
solution is available.</p>
<p>Diaspora, on the contrary, has partial implementation of standard protocols,
but no way to communicate easily with others. I was trying to crosspost from
my Known instance (or rather the one from <a href="http://known.hackens.org/">my
hacklab</a>) to our Diaspora / Twitter and Facebook
account (the famous <a href="https://indiewebcamp.com/POSSE"><span class="caps">POSSE</span></a> thing). The last
two were really easy to do, thanks to a plugin and Bridgy. There was no way to
handle the first one. So, I started to write a Known plugin to handle Diaspora
crosspost, and to look for a way to get backfeed.</p>
<p>First, how can we push content to Diaspora? Actually, there is no specific <span class="caps">API</span>
available. So, you basically have two ways:</p>
<ol>
<li>Either use the built-in Salmon protocol. It is <a href="https://wiki.diasporafoundation.org/Federation_protocol_overview#Sending">minimally
documented</a>
in the doc, and not the most practical way. I wanted to have something
working quickly, and had a look to other softwares doing such stuff, to
reuse some functions and classes. None of them was implementing it, and I
was not really in writing something like this.</li>
<li>Or use the “standard way”, at least according to the multiple scripts to
handle crossposting that I found (for instance some <a href="http://wordpress.org/plugins/wp-to-diaspora">Wordpress to
Diaspora</a> tools listed in the
wiki). Then, the basic way is to start a curl session, to handle cookies,
and to go to the login page, get the <span class="caps">CSRF</span> token, send a request with <span class="caps">POST</span>
data to log the user in (credentials and <span class="caps">CSRF</span> token), then go to another
page to get a new <span class="caps">CSRF</span> token, and post to the <span class="caps">URL</span> that the status form
posts to, as if it was a real user. Really ugly, isn’t it? =(</li>
</ol>
<p>Finally, I managed to have a basic <a href="https://github.com/Phyks/KnownDiaspora">Known to
Diaspora</a> plugin. Ok, I was able to
post to Diaspora, with a really ugly code, but it was working.</p>
<p>But then, I wanted to get backfeed from Diaspora, as it is the case for
Twitter and Facebook using Bridgy. Basically, this means that if anyone is
commenting / liking / sharing on Diaspora, I would have a notification in
Known and be able to display it under the status message. For usual
centralized silos, it is “fairly” easy: they offer a rather complete <span class="caps">API</span>, and
you just poll regularly the <span class="caps">API</span> for changes. In the worst scenariis, you scrap
the <span class="caps">HTML</span> page, but this is super ugly.</p>
<p>Diaspora promotes decentralization and is open-source, so I was expecting it
would be much easier than with silos… I had no idea of what I was wanting to
do (cf <a href="https://github.com/snarfed/bridgy/issues/198">this issue</a> on Bridgy
for the results of my research) =(</p>
<p>First, I went to their wiki, and tried to find some infos. Most of their wiki
is either outdated (describing APIs which were removed in past commits) or too
futuristic (describing things that are not and have not been implemented in
the last six months)… Finally, I found two solutions:</p>
<ul>
<li>An eventual OStatus <span class="caps">API</span> <a href="http://activitystrea.ms/">ActivityStreams</a></li>
<li>(-Scrapping-, okay not a decent idea)</li>
</ul>
<p>I could not find any further information about these, so I headed to their <span class="caps">IRC</span>
channel. It appeared that the first one was outdated and removed lately. I
never got any answer about the second =( But I got some really interesting
stuff. People wondering what is my “Diaspora handle” and making jokes about
“webfinger” which looks like ”finger“ and offering me to ”finger me as long as
I’m a female”… No comment on this last sentence, but I am here to discuss
about technical stuff and not about sexual practices.</p>
<p>Finally, the only two answers I got were ”read the wiki” (hmm…) and “use <a href="https://known.phyks.me/2015/www.rubydoc.info/github/Raven24/diaspora-federation/">this
gem</a>
which handles Diaspora federation” (but problem is I do not know Ruby, am
coding in either <span class="caps">PHP</span> or Python, and the gem is highly not documented,
especially about what it really implements). I feel like I spent two days
looking for doc on this point, and got virtually no info and support from the
community. This is definitely something that is not interesting them, in my
opinion, and I am not really willing to spend hours trying to understand
something just for a small use I may have. After all, if backfeeds do not
work, I do not care much about it…</p>
<p>More generally, most of the people that adopted Diaspora after Cyrille Borne
have now gone, or do not use it regularly. There might be some reasons. Some
of them just quit, others tried other social networks, to see how it looks
like, especially <a href="http://movim.eu/">Movim</a> which has the advantage of being
built around standard <span class="caps">XMPP</span>, extending it and trying to push a reasonable spec
each time it is needed. I am not really confident for the future of Diaspora,
and do not want to maintain something I do not use (with all the security
risks, time consumption etc) on my server, so I decided to definitely quit
Diaspora. For me, it failed in defending its principles, and my experience
from the last two days shows me that it is not much better than centralized
silos on some points, which are precisely the points more closely related to
my ideas and principles. Moreover, developing for Diaspora means developing a
niche software for a few (hundreds ?) of persons. If it takes so much time to
get just basic behaviours, in my opinion, it is not worth the cost. Then, why
would one run his own instance, if it does not carry much more good stuff than
using a silo?</p>I can now crosspost to Diaspora2015-01-18T16:35:00+01:002015-01-18T16:35:00+01:00Phykstag:localhost,2015-01-18:/Blog/output/2015/01/i-can-now-crosspost-to-diaspora.html<p>Just to say that I am writing a plugin to be able to crosspost to Diaspora
from my Known instance.</p>
<p>At the moment, the plugin is quite buggy and supports only the notes and
posts. It is available <a href="https://github.com/Phyks/knowndiaspora">here</a> (mind
the case-sensitivity).</p>
<p>Ok, I admit this blog post is just …</p><p>Just to say that I am writing a plugin to be able to crosspost to Diaspora
from my Known instance.</p>
<p>At the moment, the plugin is quite buggy and supports only the notes and
posts. It is available <a href="https://github.com/Phyks/knowndiaspora">here</a> (mind
the case-sensitivity).</p>
<p>Ok, I admit this blog post is just an excuse to test cross-posting of long
entries to Diaspora… =P</p>Passage à Known2015-01-12T21:53:00+01:002015-01-12T21:53:00+01:00Phykstag:localhost,2015-01-12:/Blog/output/2015/01/passage-a-known.html<p>Cela fait quelques semaines que je teste <a href="https://withknown.com/">Known</a> sur <a href="https://known.phyks.me/">mon instance</a>. Je publie systématiquement mes articles aux deux endroits, sur mon blog et sur Known, depuis quelques temps, et je pense migrer définitivement car je suis pleinement satisfait par Known et ne voit pas vraiment l’intérêt de maintenir deux …</p><p>Cela fait quelques semaines que je teste <a href="https://withknown.com/">Known</a> sur <a href="https://known.phyks.me/">mon instance</a>. Je publie systématiquement mes articles aux deux endroits, sur mon blog et sur Known, depuis quelques temps, et je pense migrer définitivement car je suis pleinement satisfait par Known et ne voit pas vraiment l’intérêt de maintenir deux espaces différents avec le même contenu (sans compter que ce blog a certains bugs, comme le décompte des articles dans le panneau de gauche…).</p>
<p>Du coup, quelques changements mineurs sont à prévoir. Il risque d’y avoir pas mal de liens morts, vu que je ne vais pas pouvoir rerouter tous mes articles vers les nouvelles URLs légèrement différentes. Mais tous mes anciens articles seront sur mon instance de Known.</p>
<p>Le flux <span class="caps">RSS</span> va aussi changer d’adresse, pensez à mettre à jour les adresses ! La nouvelle adresse sera <a href="https://known.phyks.me/?_t=rss">https://known.phyks.me/?_t=rss</a> (ou de façon équivalente <a href="https://phyks.me/?_t=rss">https://phyks.me/?_t=rss</a> quand la migration sera terminée, ce qui n’est pas encore le cas, les deux liens resteront valables dans le futur). Je pense migrer définitivement d’ici la fin de la semaine.</p>
<p>Sino, je réfléchis aussi pour remplacer mon <a href="http://sebsauvage.net/wiki/doku.php?id=php:shaarli">Shaarli</a> sur Known (vu qu’il gère les “likes” et les marque-pages), mais c’est en cours et sera sûrement l’objet d’un prochain article.</p>Self-hosting Firefox sync 1.52015-01-11T23:30:00+01:002015-01-11T23:30:00+01:00Phykstag:localhost,2015-01-11:/Blog/output/2015/01/self-hosting-firefox-sync-15.html<p>I used to self-host Firefox Sync but since the new Firefox Accounts + Firefox Sync (appeared in Firefox 29), it has became more difficult to self-host it, and I didn’t take time to handle it. However, lately, the doc has greatly improved and it’s rather straightforward. Although, most of …</p><p>I used to self-host Firefox Sync but since the new Firefox Accounts + Firefox Sync (appeared in Firefox 29), it has became more difficult to self-host it, and I didn’t take time to handle it. However, lately, the doc has greatly improved and it’s rather straightforward. Although, most of the doc available (for Firefox Accounts mostly) is mainly oriented toward dev and testing rather than setting a production ready instance. So, I will try to describe as best as I can the different steps I took to get a working setup.</p>
<p>Please refer at any time to the <code>README</code> file in the cloned repo, which contains very useful information that may be missing in this article. Please report me also any such information, so that I can keep an up-to-date comprehensive guide on this installation.</p>
<p>As said before, there are now two components that are needed for the sync server. The first one is the sync server itself, written in Python, as it already used to be in the past. The new one is the Firefox Account instance, written in Node, which is used as a common authentication mechanism for all the Mozilla services like Sync, Firefox Marketplace, Firefox’s find-my-device, etc.</p>
<p>It is <strong>optional</strong> to self-host the Firefox accounts part, and you can rely on the Mozilla servers if you want. They will only do the authentication part, and their server will never handle your plaintext password, so that they cannot in any case decrypt your data, as explained <a href="https://blog.mozilla.org/services/2014/05/08/firefox-accounts-sync-1-5-and-self-hosting/">here</a>. This is a good compromise if you want a quick and easy running solution.</p>
<p>At the beginning, I was planning on selfhosting everything for myself. But the Firefox Accounts part is really tricky to set, and you should know that no official Mozilla server will be able to handle authentification against a non-Mozilla Firefox Accounts server. This means that if you use your own Firefox Accounts server, it can be used for Sync (and for FindMyDevice if you have a FirefoxOS phone and tweak a bit), but not for the Marketplace or so. So I decided it was not worth the energy and time passed to update it and keep track of security updates and selfhost only the Firefox Sync part.</p>
<h2>Firefox sync server</h2>
<p>Actually, the doc is really good for this part and you should just read <a href="https://docs.services.mozilla.com/howtos/run-sync-1.5.html">the official instructions</a>. A french doc is available <a href="https://dattaz.fr/blog/?id=13">on dattaz’s blog</a>.</p>
<p>For further configuration, the <code>syncserver.ini</code> file is well commented and the comments should be self-explanatory.</p>
<h2>Firefox Accounts server</h2>
<p>To self-host this component, you will need node and npm. Firefox Account itself is split in multiple components: an auth server, a database backend and a content server to serve the interface. We will install all the firefox accounts part in <code>/home/fxa</code>. The official doc is available <a href="https://docs.services.mozilla.com/howtos/run-fxa.html#howto-run-fxa">here</a>.</p>
<h3>Firefox Accounts authentication server</h3>
<p>Let us first focus on the authentication server and its database backend. First step is to install the necessary stuff: <code>node</code>, <code>npm</code>, <code>pgrep</code>, <code>libgmp-dev</code> and <code>mysql</code> (or <code>mariadb</code>). The <code>train-NN</code> branches are kind of tagged versions, and you should git checkout the latest, which is 27 as of writing this article.</p>
<div class="highlight"><pre><span></span><code><span class="nb">cd</span><span class="w"> </span>/home/fxa
git<span class="w"> </span>clone<span class="w"> </span>git<span class="w"> </span>clone<span class="w"> </span>git://github.com/mozilla/fxa-auth-server.git
git<span class="w"> </span>checkout<span class="w"> </span>train-27
<span class="nb">cd</span><span class="w"> </span>fxa-auth-server
npm<span class="w"> </span>install
</code></pre></div>
<p>This will clone and install the auth-server. Then, let’s clone the database backend as well:</p>
<div class="highlight"><pre><span></span><code><span class="nb">cd</span><span class="w"> </span>/home/fxa
git<span class="w"> </span>clone<span class="w"> </span>https://github.com/mozilla/fxa-auth-db-server
<span class="nb">cd</span><span class="w"> </span>fxa-auth-db-server
npm<span class="w"> </span>install
</code></pre></div>
<p>In <code>fxa-auth-db-server/</code>, you will have to edit your database credentials. Edit (or create) the file <code>.fxa_dbrc</code> and put the following content inside:</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"master"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"user"</span><span class="p">:</span><span class="w"> </span><span class="s2">"fxa"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"mysecret"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"database"</span><span class="p">:</span><span class="w"> </span><span class="s2">"fxa"</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="nt">"slave"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"user"</span><span class="p">:</span><span class="w"> </span><span class="s2">"fxa"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"mysecret"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"database"</span><span class="p">:</span><span class="w"> </span><span class="s2">"fxa"</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Where <code>fxa</code> is a previously created user in <code>MySQL</code>, with restricted rights and full rights over a database <code>fxa</code>, and <code>mysecret</code> is its password.</p>
<p>Then, we will create a new user to handle firefox account stuff, <code>fxa</code> and give him rights on the previously created repos:</p>
<div class="highlight"><pre><span></span><code>useradd<span class="w"> </span>--home<span class="w"> </span>/home/fxa<span class="w"> </span>fxa
chown<span class="w"> </span>-R<span class="w"> </span>fxa:fxa<span class="w"> </span>/home/fxa
su<span class="w"> </span>fxa
</code></pre></div>
<p>Let us initialize the database with</p>
<div class="highlight"><pre><span></span><code><span class="nv">NODE_ENV</span><span class="o">=</span>prod<span class="w"> </span>node<span class="w"> </span>bin/db_patcher.js
</code></pre></div>
<p>and the server keys with</p>
<div class="highlight"><pre><span></span><code><span class="nb">cd</span><span class="w"> </span>../fxa-auth-server
<span class="nv">NODE_ENV</span><span class="o">=</span>prod<span class="w"> </span>node<span class="w"> </span>./scripts/gen_keys.js
</code></pre></div>
<p>Let us customize the configuration:</p>
<div class="highlight"><pre><span></span><code>cd config
cp dev.json prod.json
vim prod.json
</code></pre></div>
<p>(there is basically not much to do, except tweaking the smtp settings)</p>
<h3>Firefox Accounts content server</h3>
<p>First, let us clone the repo:</p>
<div class="highlight"><pre><span></span><code><span class="nb">cd</span><span class="w"> </span>/home/fxa
git<span class="w"> </span>clone<span class="w"> </span>https://github.com/mozilla/fxa-content-server/
chown<span class="w"> </span>-R<span class="w"> </span>fxa:fxa<span class="w"> </span>fxa-content-server
<span class="nb">cd</span><span class="w"> </span>fxa-content-server
</code></pre></div>
<p>Then, checkout the last version, using git tags. As of writing this article, it is <code>git checkout v0.27.0</code>. The tagged versions of the content server should be in sync with the <code>train-NN</code> branches in the auth-server, and you should clone the same version number for the two of them (at least as of writing this article). Install the dependencies with <code>npm install</code>.</p>
<p>Customize the config. In <code>server/config/production.json</code>, add (change what has to be changed):</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"EXISTING_KEY"</span><span class="p">:</span><span class="w"> </span><span class="s2">"…"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"client_sessions"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"cookie_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"session"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"secret"</span><span class="p">:</span><span class="w"> </span><span class="s2">"YOU MUST CHANGE ME"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"duration"</span><span class="p">:</span><span class="w"> </span><span class="mi">86400000</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p><strong>Note:</strong> The <span class="caps">README</span> file says that this should go in <code>.fxa_dbrc</code> file. But it is not yet supported and the doc is not right on this point, cf <a href="https://github.com/mozilla/fxa-auth-db-server/issues/107">this issue</a>. This might however change in the near future. Have a look.</p>
<p>Finally, run <code>grunt server:dist</code> to build production resources (will take some time) and run a local server on port 3030 with production resources.</p>
<h3>Launch all the stuff</h3>
<p>Ideally, this should be run in a <code>screen</code> (or as daemons) with less privileged user (such as the previous <code>fxa</code> user).</p>
<div class="highlight"><pre><span></span><code>screen<span class="w"> </span>-S<span class="w"> </span>fxa
<span class="nb">cd</span><span class="w"> </span>~fxa/fxa-auth-db-server
<span class="nv">NODE_ENV</span><span class="o">=</span>prod<span class="p">;</span><span class="w"> </span>npm<span class="w"> </span>start
<span class="c1"># (new window)</span>
<span class="nb">cd</span><span class="w"> </span>~fxa/fxa-auth-server
<span class="nv">NODE_ENV</span><span class="o">=</span>prod<span class="p">;</span><span class="w"> </span>node<span class="w"> </span>./test/mail_helper.js
<span class="c1"># (new window)</span>
<span class="nb">export</span><span class="w"> </span><span class="nv">NODE_ENV</span><span class="o">=</span>prod<span class="p">;</span><span class="w"> </span>node<span class="w"> </span>./bin/key_server.js<span class="w"> </span><span class="p">|</span><span class="w"> </span>node<span class="w"> </span>./bin/notifier.js<span class="w"> </span>>/dev/null
<span class="c1"># (new window)</span>
<span class="nb">cd</span><span class="w"> </span>~fxa/fxa-content-server
grunt<span class="w"> </span>server:dist
</code></pre></div>
<p>You can head to <code>your_ip:3030</code> to create a Firefox Account. You may want to setup an Apache proxy to serve it, but this is not covered in this guide. For the last settings in Firefox, I let you have a look at <a href="https://docs.services.mozilla.com/howtos/run-fxa.html#howto-run-fxa">the official doc</a>.</p>
<p>Of course, you can run it behind an Apache proxy, or do more advanced configuration. However, as I am not using it and considered useless to spend much time configuring it, I did not look at these parts.</p>Personal review of the Lenovo Thinkpad T4402015-01-08T17:40:00+01:002015-01-08T17:40:00+01:00Phykstag:localhost,2015-01-08:/Blog/output/2015/01/personal-review-of-the-lenovo-thinkpad-t440.html<p>I recently changed my laptop and bought a Lenovo T440. I used to have a Clevo <span class="caps">W150ERQ</span> (actually a <span class="caps">LDLC</span> Saturne, but <span class="caps">LDLC</span> is just rebranding Clevo’s laptops). It was a really good laptop, but I bought it at a time when I when I was looking for a …</p><p>I recently changed my laptop and bought a Lenovo T440. I used to have a Clevo <span class="caps">W150ERQ</span> (actually a <span class="caps">LDLC</span> Saturne, but <span class="caps">LDLC</span> is just rebranding Clevo’s laptops). It was a really good laptop, but I bought it at a time when I when I was looking for a powerful computer more than a light notebook, and it was way too heavy. Plus as a side effect, it had a poor battery (3 hours autonomy maximum) which I magically managed to maintain, thanks to much tweaks, and despite the battery having lost almost 50% of its original capacity. Finally, it was built around <span class="caps">NVIDIA</span> optimus technology, that was lacking serious Linux support.</p>
<h2>Criteria</h2>
<p>So, my goals when looking for a new laptop were that it was small, lightweight (the previous Clevo was 3kgs), powerful enough for my needs (no need for a high end <span class="caps">GPU</span> as I’m not doing gaming on my laptop, but still some decent <span class="caps">CPU</span>, with built-in <span class="caps">AES</span> encryption capabilities), a large autonomy, to be able to travel without worrying about finding a power plug and a large matte screen (no less than 14”, and <span class="caps">HD</span> resolution). One that was fitting almost all my needs was the Lenovo T440, with some options (intel i5 instead of the i3 in the base model, and <span class="caps">HD</span> screen). I had time to play a bit with it, so I write some feedback, in case it can be useful to anyone. This feedback might be updated as time passes. Note that I won’t comment anything related to Windows, as there are plenty of infos about this notebook running Windows on the web, and I never used it with Windows.</p>
<h2>Windows refund</h2>
<p>Unfortunately, no Windows refund is available with Lenovo (it came with Windows 8.something preinstalled). They would only refund the entire laptop =(</p>
<h2>Price</h2>
<p>I did not want to spend too much on my laptop. Especially, I did not want to pay it more than 1k€, which is often the price for such laptops. I got mine with <span class="caps">HD</span> screen, the biggest external battery and Intel i5 for 800€ (with 200€ discount from Lenovo).</p>
<h2>External aspect</h2>
<p>The laptop is quite thin, and matte, which makes it look very elegant :) The charger is very slim, and the total weight is very reasonable, below 2kgs with extra battery and charger. The screen looks nice and comfortable, although it does not have very wide viewing angles (not to say they are rather narrow…). It’s very bright and can be set at any level between 0 and 100%, with standard Linux tools such as <code>xbacklight</code> (good point compared to the previous Clevo which only had a few possible levels). It has an internal battery (25Wh) and an extra external battery can be used for more power.</p>
<p>It has standard ports, 2 USBs, a mini display port, a <span class="caps">VGA</span> port, an <span class="caps">SD</span> card reader and a true ethernet port. It only has one single port for the micro and the headphones.</p>
<h2>Opening it</h2>
<p>I took one of the cheaper model, and wanted to put an <span class="caps">SSD</span> I had from before inside, to avoid having mechanical drive in such a laptop. So, I had to open it, before anything else. Contrary to the other Lenovo laptops, this one is very slim and very compact. Then, there is no easy access to the components (direct access to memory chips or hard drives for instance). You have to take out the whole base cover to change any component inside. That may sound impressive, but is not very difficult to do (but will mean higher costs if you don’t want to do it yourself).</p>
<p>First, disable the internal battery in the <span class="caps">BIOS</span>. Then, the best way I found to do it is to remove the 8 screws (standard screw driver) below the laptop and unclipse the base cover, starting from the rear (below the external battery). Do not use any tool, but your nail, to prevent any damage to the base cover, and to easily remove it. Note that the screws cannot be fully removed from the base cover, and that you should not have to force at any time. If so, check that the screws are well unscrewed, and if it still need some force applied, try opening the other side, to loop back to this position.</p>
<p>I had never opened such a computer before, and it took me around 30 minutes to swap the hard drives.</p>
<p>For info, if you have a version without 3G modem, you have an M2 slot (42mm if I remember correctly) available to put an extra <span class="caps">SSD</span>. This slot may be already taken by the <span class="caps">SSD</span> cache in case you chose an <span class="caps">HDD</span> + <span class="caps">SSD</span> cache.</p>
<h2>Support status under Linux</h2>
<p>I run ArchLinux, so my remarks may not be applicable to other distributions. The laptop has <a href="https://wiki.archlinux.org/index.php/Lenovo_ThinkPad_T440s">a wiki page</a> in the doc. It is for the variant with a touchscreen but most remarks are applicable. Once the necessary packages available, everything works just fine.</p>
<p>I chose not to fight with <span class="caps">UEFI</span>, and use the regular <span class="caps">BIOS</span> (<span class="caps">BIOS</span> emulation) instead. I just had to disable SecureBoot and choose it in the <span class="caps">BIOS</span>. The <span class="caps">BIOS</span> is really nice designed, with many options (Fn is the leftmost key on the keyboard for instance, but you can swap Fn and Ctrl in the <span class="caps">BIOS</span>, which is very practical as I prefer this layout). I installed the Intel drivers for Xorg, the synaptics driver for the ClickPad and the <code>iwlwifi</code> drivers for the wifi card, and everything worked nice out of the box.</p>
<p>I use i3wm, so I did not have any mappings predefined for the function keys. All of them are recognized as Xf86 function tools, and I just needed a config line in my i3 config file to assign them to <code>xbacklight</code> calls to increase and decrease brightness. Same thing for basically all the other function keys, nothing difficult to notice there.</p>
<p>The backlight for the keyboard works also out of the box. It is either fully hardware or well supported under Linux, but I did not have to install anything to use it. There are two levels of illumination available.</p>
<h2>Autonomy</h2>
<p>I did not do any power saving as of now, and the laptop is really impressive on this point! I was fearing that the preinstalled Windows may be overoptimized for the laptop, and that I would have a poor autonomy on Linux, but that’s not the case at all.</p>
<p>I have an internal 25Wh battery, and an external 75Wh battery. The laptop was marketed around 15 hours of autonomy, and I must say that it’s actually running 15 hours. It is consuming no more than 5W with Wifi connectivity (and browsing the web), my <span class="caps">SSD</span>, and backlight set to 10%. That’s really impressive and Intel has made a very good job with their latest generation of core i5. I compiled some stuff (Python <code>matplotlib</code>), still with 10% backlight, and jumped up to 15W, no more. For similar performances (at least, similar felt performances), my previous Clevo was consuming around 40W.</p>
<p>Then, out of the box, with the external battery, one can easily work in continuous for between 10 and 15 hours. Tests say that it can run up to 28 hours in idle mode. Totally satisfied on this point !</p>
<h2>Webcam</h2>
<p>Not much to say, it works. It is an integrated webcam so nothing particularly good or bad.</p>
<h2>Bluetooth</h2>
<p>Not tested yet.</p>
<h2><span class="caps">SD</span> card reader</h2>
<p>Not tested yet.</p>
<h2>Audio quality</h2>
<p>Not much to say. Not very bad, not exceptionally good. :)</p>
<h2>Fan and temperature</h2>
<p>The <span class="caps">CPU</span> in normal use is at around 40°C. The laptop does not get very hot and is very silent (I’ve never heard the fan as of today).</p>
<h2><code>Tp_smapi</code></h2>
<p><code>Tp_smapi</code> is a tool to handle some <span class="caps">ACPI</span> calls for Thinkpad. It can (apparently) handle the <span class="caps">HDAPS</span> feature, to detect shocks and avoid damages to the hard drive. As I have a <span class="caps">SSD</span>, I do not use this feature.</p>
<p>A more interesting tool is <a href="https://aur.archlinux.org/packages/tpacpi-bat/">tpacpi-bat</a> available from the <span class="caps">AUR</span>, which allows you to set thresholds for charging and discharging the battery. This way, you can set thresholds at 40% and 80% to keep the battery in its best area, according to Lenovo advices.</p>
<p>This works really nice and is well documented <a href="https://aur.archlinux.org/packages/tpacpi-bat/">in the Archwiki</a>.</p>
<h2>Touchpad</h2>
<p>There is a trackpad in the keyboard (but I’m not a huge fan of trackpads). The touchpad is a bit tricky to handle correctly. Indeed, it is composed of a single sensitive area (without any physical buttons) and is a single button (the whole touchpad can be clicked, but as far as I know, it is a single button). Then, you have to map it correctly in Xorg, so that you define “Virtual buttons” and couple the position of your finger on the touchpad to the click event. This can be done quite easily and people have posted many configurations such as <a href="http://rscircus.org/post/72978821261/t440s-clickpad-fix-which-feels-good">this one</a>.</p>
<p>I did not have yet a fully working configuration for my use, and this needs some tweaks, but nothing really problematic, in my opinion. I also use <code>syndaemon</code> as it is very easy to hit the touchpad accidentally while typing.</p>
<h2>Conclusion</h2>
<p>This is a great laptop, in my opinion, with minor points that could be improved. But, it has a really good price / performance ratio. The autonomy is really impressive, in particular and it works very well out of the box under Linux.</p>
<p>For a full test (more hardware and pure perfs than Linux compatibility and so on), <a href="http://www.notebookcheck.net/Review-Update-Lenovo-ThinkPad-T440s-20AQ0069GE-Notebook.110564.0.html">here is one</a>.</p>Publishing through the Known API2015-01-07T16:20:00+01:002015-01-07T16:20:00+01:00Phykstag:localhost,2015-01-07:/Blog/output/2015/01/publishing-through-the-known-api.html<p>As stated in <a href="http://localhost/Blog/output/2015/01/thoughts-on-blogging-engine.html">my last article</a>, I’m considering moving my blog to Known. But I’m not a huge fan of <span class="caps">WSIWYG</span> editors. I find it handy sometimes, and can enjoy editing in Markdown on Github, but for a long post, I really prefer writing content on my own …</p><p>As stated in <a href="http://localhost/Blog/output/2015/01/thoughts-on-blogging-engine.html">my last article</a>, I’m considering moving my blog to Known. But I’m not a huge fan of <span class="caps">WSIWYG</span> editors. I find it handy sometimes, and can enjoy editing in Markdown on Github, but for a long post, I really prefer writing content on my own text editor and sending it online after. Plus I can maintain drafts this way and benefits from spell checking abilities with my dictionary.</p>
<p>My goal is then to find a way to post to Known from my own <span class="caps">PC</span>, using some kind of local app or script.</p>
<p>That’s really really easy in fact, as every single <span class="caps">URL</span> in Known is also an <span class="caps">API</span> endpoint.</p>
<p>But, first, let’s talk about a standard way of doing it, that is not Known specific. You can install the <a href="https://github.com/idno/indiepub">IndiePub</a> plugin in Known to enable a <a href="https://indiewebcamp.com/Micropub">MicroPub</a> endpoint in Known.</p>
<p><em>Note</em>: Take care of cloning the repo correctly in <code>IdnoPlugins</code> as the case matters. Indeed, I cloned it as <code>indiepub</code> (lower case) and it took me some time to figure out why it was not working. After having renamed the folder <code>IndiePub</code> everything works fine.</p>
<p>Micropub is a standard way of publishing content to another website, so that, after having received an authorization from you, an app can publish content to your website. Some kind of standard (part of the <a href="https://indiewebcamp.com/">IndieWebCamp</a> stuff) <span class="caps">API</span>, like the one used by apps on silos to post things on your page.</p>
<p>Then, you can use anything that speaks the Micropub to publish on your website. The most famous one may be <a href="http://quill.p3k.io/">Quill</a>, a webapp by <a href="http://aaronparecki.com/">aaronparecki</a>. Most of the available tools are written in <span class="caps">PHP</span>, but you can also find some libs in <a href="https://indiewebcamp.com/Python">Python</a> to handle this kind of stuff (although there does not seem to be any Micropub publishing libraries at the moment).</p>
<p>But known also offers its own <span class="caps">API</span> which may be way easier to use, at least to start with. It can be used in basically the same way, but you don’t have to worry as much about authentication and endpoints discovery.</p>
<p>So, every <span class="caps">URL</span> endpoint is also an <span class="caps">API</span> endpoint. For instance, on your Known homepage, if you click on “status update” to post a new status update, and have a look at the form that appears, you will notice that it posts data to <code>/status/edit</code> (actually, when you click the “status update” button, you will notice there is a link on it to <code>/status/edit</code>, in case you do not have <span class="caps">JS</span> enabled). The form is a <code>POST</code> form and you have a <code>body</code> textarea. Let’s try to have a look at the page at <code>status/edit</code> (with your browser). As you can see, you have the same form that allows you to publish a new status. But you can also directly send a query to this address, to post a new entry.</p>
<p>For this purpose, you will have to go to your Settings, in the “Tools and apps” menu and get your <span class="caps">API</span> key. Then, you must authenticate every query you send to the <span class="caps">API</span>. To this purpose, Known uses a <span class="caps">HMAC</span> signature, to prevent from sending the <span class="caps">API</span> key in plaintext over the network. Your <span class="caps">API</span> key is private and should be kept secret on your side. You will have to create a <span class="caps">HMAC</span> signature, using sha256, of the <span class="caps">URL</span> you query, thanks to your <span class="caps">API</span> key. Snippets to do this in many languages are available <a href="http://www.jokecamp.com/blog/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/">here</a>. In these snippets, <code>message</code> is the <span class="caps">API</span> endpoint you query (for instance <code>/status/edit</code> in our previous example) and key is your <span class="caps">API</span> key.</p>
<p>Then, you have to add specific headers to your query to authenticate. These are <code>X-KNOWN-USERNAME</code> which should be equal to your Known username and <code>X-KNOWN-SIGNATURE</code> which should be set to the previously computed signature. This can be done very easily with <code>curl</code> thanks to the command (updating the values of the headers to the correct one)</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>curl<span class="w"> </span>-H<span class="w"> </span><span class="s2">"X-KNOWN-USERNAME: USERNAME"</span><span class="w"> </span>-H<span class="w"> </span><span class="s2">"X-KNOWN-SIGNATURE: SIGNATURE"</span><span class="w"> </span>http://known.example.org/status/edit
</code></pre></div>
<p>For quick tests of the <span class="caps">API</span>, you can use the <code>API Tester</code> plugin, which will take care of forging the correct query based on your inputs. Then, you do not have to worry about building a <span class="caps">HMAC</span> signature and so on. You can also use it to check that the requests you send have valid signature (by comparing the generated one and yours) and so on.</p>
<p>Then, you have to send a payload beside the headers. This payload will be the actual content that will be posted. You should pass it as a <span class="caps">JSON</span> encoded array (but you can also use other formats, see the <code>API Tester</code> plugin or directly the source code), as it is the easiest way. You should send it with <code>POST</code>.</p>
<p>Let’s have a look in details at our previous example, status update posting, <em>via</em> <code>/status/edit</code>. As we saw, the basic thing to send is the actual content of the status update, through the <code>body</code> field. Then, to post a “blah” status, the <span class="caps">JSON</span> encoded payload would look like</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span><span class="nt">"body"</span><span class="p">:</span><span class="w"> </span><span class="s2">"blah"</span><span class="p">}</span>
</code></pre></div>
<p>And you can post it with the following curl command:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>curl<span class="w"> </span>-H<span class="w"> </span><span class="s2">"X-KNOWN-USERNAME: USERNAME"</span><span class="w"> </span>-H<span class="w"> </span><span class="s2">"X-KNOWN-SIGNATURE: SIGNATURE"</span><span class="w"> </span>-X<span class="w"> </span>POST<span class="w"> </span>--data<span class="w"> </span><span class="s1">'{"body": "blah"}'</span><span class="w"> </span>http://known.example.org
</code></pre></div>
<p>And here we go ! Your first status update posted through the <span class="caps">API</span> !</p>
<p>Depending on the choosen <span class="caps">API</span> endpoint, you might want to pass extra parameters. For example, with “posts” (<code>entry/</code> in the URLs), you have both a title (logically called <code>title</code>) and a body (as previously). Then, the payload for a post with title “blah” and content “blahblah” will look like</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span><span class="nt">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"blah"</span><span class="p">,</span><span class="w"> </span><span class="nt">"body"</span><span class="p">:</span><span class="w"> </span><span class="s2">"blahblah"</span><span class="p">}</span>
</code></pre></div>
<p>Most of the endpoints also offer the ability to tweak the <code>created</code> param, to post a content in the paste or in the future (defaults to now). This is what I used to upload the articles from my previous blog to Known, for instance. This parameter is passed to the <a href="http://php.net/manual/fr/function.strtotime.php"><code>strtotime</code></a> <span class="caps">PHP</span> function, and should then be in a valid format for this function. Many valid formats are available, including relative ones (see the <a href="http://php.net/manual/fr/function.strtotime.php">doc</a> for more info), but the most straight-forward one, with absolute dating, might be to use <span class="caps">ISO</span> 8601, that is <code>YYYY-MM-DD HH:MM:SS</code>.</p>
<p>The common endpoints that I have used so far are <code>/status/edit</code> and <code>/entry/edit</code> to post, respectively, status updates and long posts. A working script example (in Python) can be found <a href="https://git.phyks.me/Phyks/blog/blob/master/known.py">on my blog repository</a> (taking an entry in the format I used to have for my previous blog, and posting it to Known).</p>
<p>Finally, if you want to use extra endpoints, there is no ready to use doc at the moment (see <a href="issue #225">https://github.com/idno/idno/issues/225</a> on Github), but the source code is very easily readable, once you know where to look for the infos :) So, you should know that almost everything in Known is an <code>Entity</code> (which is a common way to describe the content you post). Then, all the specific types of <code>Entities</code> (status, long posts, photos, like etc.) are handled by plugins, located in the <code>IdnoPlugins</code> folder. For instance, status are handled by <code>IdnoPlugins/Status</code> and long posts are handled by <code>IdnoPlugins/Text</code>.</p>
<p>Every plugin declares its routes in the <code>Main.php</code> file. For instance, the <code>Status</code> plugin declares the routes <code>/status/edit</code> (post a new status), <code>/status/edit/([A-Za-z0-9]+)</code> (edit an existing status, the last parameter being the id of the status) and <code>/status/delete/([A-Za-z0-9])</code> (delte a status, same thing as the previous one). Every plugin also declares a content-type which are infos about the type of content it manages, in <code>ContentType.php</code>. Finally, looking in the <code>Pages/</code> folder, you will find scripts to handle the routes. For instance, for <code>/status/edit</code>, you will find in <code>Pages/Edit.php</code> the associated routes, to get and post content.</p>Thoughts on blogging engine2015-01-05T17:35:00+01:002015-01-05T17:35:00+01:00Phykstag:localhost,2015-01-05:/Blog/output/2015/01/thoughts-on-blogging-engine.html<p>For now, I am using my own custom made Python script to handle my static blog with a Git backend, <a href="https://github.com/Phyks/Blogit">Blogit</a>. It is becoming heavy and difficult to maintain, and I would better do a good refactor. However, many scripts of this kind exists around here, like <a href="http://jekyllrb.com/">Jekyll</a> in Ruby …</p><p>For now, I am using my own custom made Python script to handle my static blog with a Git backend, <a href="https://github.com/Phyks/Blogit">Blogit</a>. It is becoming heavy and difficult to maintain, and I would better do a good refactor. However, many scripts of this kind exists around here, like <a href="http://jekyllrb.com/">Jekyll</a> in Ruby, or <a href="http://blog.getpelican.com/">Pelican</a> in Python. As I do not aim at developping a fully-featured alternative to these scripts, I am considering moving to one of these, and let others with better goals handle it. It is not always useful to reinvent the wheel and especially in this case, as I have very basic needs.</p>
<p>I played a bit with Pelican and Jekyll. First, I played much more with Pelican than with Jekyll. That is because I know Python and feel more comfortable with Pelican. Also, it seems more robust, extensible and well designed than Jekyll. At least, that’s the overall impression I have, that Pelican is a bit cold, but very powerful, whereas Jekyll is warmer, but more on the blingbling side also. Pelican supports ReStructuredText besides Markdown and <span class="caps">HTML</span>, and it was very straightforward to convert my articles to the Pelican file format (especially for metadata) and keep the same URLs. There is a bunch of plugins and themes for many things (git backend, specific parsers, search engine etc) but some of them are outdated. It’s relatively easy to get something working quickly and I think this is a really good static blog engine, very efficient. For more info about it, you can check out <a href="http://a3nm.net/blog/pelican.html">this blog post</a> about a recent migration from <a href="https://gitorious.org/fugitive">fugitive</a>, shell scripts to statically build a blog on top of a git repo, to Pelican.</p>
<p>Then, I was about to migrate to Pelican when I heard about <a href="https://withknown.com/">Known</a> at a <a href="http://www.meetup.com/Paris-Meetup-pour-la-decentralisation-dInternet/events/218943348/">Decentralization Meetup</a> at Mozilla Paris. I had already heard about the <a href="https://indiewebcamp.com/">IndieWebCamp</a> but never had time to look in depth at their wiki and the stuff they were building.</p>
<p>I started to think again about blogging, microblogging and social networking, and I think their approach may fix some of the core problems I experience with Diaspora. For now, I am using my static blog to publish articles, and I am (finally not so much) using <a href="https://github.com/diaspora/diaspora/">Diaspora</a> as a social network.</p>
<ol>
<li>First, Diaspora is yet another thing to monitor. I like to have my <span class="caps">RSS</span> reader running in the background, I periodically check the news. I have my emails also. Diaspora means yet another thing to watch for, something not standard (it is not emails, it is not <span class="caps">IRC</span> / <span class="caps">XMPP</span> and it is not <span class="caps">RSS</span> or equivalent feeds) and the community on Diaspora is quite small compared to the one on the other medium. Equivalently, I do not know enough people on Diaspora to want to have it running and check it regularly.</li>
<li>Diaspora has a big flaw in its implementation, as <a href="http://blog.exppad.com/article/really-social-syndication">other already wrote</a> (article in French). It is oriented toward and promoting decentralization, and encourage each one to run its pod. But running its pod is not very interesting as the federation is not complete in Diaspora. For now, we have “silos”, fully centralized, such as Twitter and Facebook ; self-hostable “silos” such as <a href="http://elgg.org/">elgg</a> (centrally decentralized networks) and fully decentralized networks like Diaspora. But, as soon as you and your contacts are on different pods, you won’t be able to see their own contact lists, to find new people to follow. Similarly, you won’t be able to follow hashtags, as they are not federated. I’m alone on my pod, and if I follow <code>#firefoxos</code>, I will only follow <em>my</em> articles tagged with this hashtag. Not very interesting, eh ?</li>
</ol>
<p>The core idea behind IndieWebCamp is not to build a social network but to own <em>your</em> data (see <a href="https://aaronparecki.com/articles/2015/01/04/1/owning-my-data-in-2014">this article</a> for example). So, why talking about Diaspora ? Because they are thinking that you should be able to communicate with others in both a user-readable and machine-readable way. But, you might already have friends on Twitter / Facebook / Instagram etc. Rather than quitting them and moving to a new platform, the goal is to be able to still talk to them, in the meantime before their migration, but to have a dump of every content you post on <em>your</em> server. As it focuses on the protocols rather than the implementation, each user may have its own baked implementation, and many of them are not (yet ?) open-sourced (such as <a href="https://aaronparecki.com/">aaronparecki’s website</a>). For now, one of the more developped and supported one seems to be Known, which was presented during the Meetup. It lets you handle microblogging, blogging, photo sharing and many more out of the box, and fully implements the protocols to communicate with other instances and is extensible through plugins. To see it in action, you can have a look at <a href="http://werd.io/">the instance of the co-founder</a>.</p>
<p>Then, rather than having multiple sites and services, each one with a partial dump of your content, everything is centralized at one place, and your Known instance gets a dump copy of every content you put online.</p>
<p>The basic idea is to use the served <span class="caps">HTML</span> and put some extra content to parse it easily with a machine. This means that both the user and the machine see the same page and can handle the same content. This is done through the use of specific classes on elements to tag them according to their type, to say that this is a post, this is an image and this is a contact card. This way, it becomes really easy to extract content from your website, using XPath for instance. And they are working on implementing favorites, reply-to, reposts and so on.</p>
<p>Thanks to <a href="https://indiewebcamp.com/Bridgy">Bridgy</a> you can have bridges with existing silos, and many apps let you get more bridges, such as <a href="https://ownyourgram.com/">OwnYourGram</a>. Using <a href="https://indiewebcamp.com/Webmention">webmentions</a>, you can post on <em>your</em> website to comment a post on someon’s else. See <a href="http://werd.io/2014/being-a-human-on-the-internet-and-discovering-my-non-throttleable#comments">this post</a> for example. Comments are actually hosted on the instance of any user, and a copy is made on this specific instance. Comments can come from Facebook and Twitter also, and virtually any website implementing the open protocol or having a bridge.</p>
<p>I thought again about my static blog. It is dead simple, and enough for my needs. But this is not always very practical as I need to have a computer with a text editor and git to commit and publish, which I do not have always with me. But having a dynamically generated blog is something really heavy and overkill for my need. Known seems to be a good compromise, it is written in <span class="caps">PHP</span> (and then easily hackable), it seems to be lightweight, and offers functionalities which are worth the overhead. Plus every route can be used as an <span class="caps">URL</span> as well, which means that I can continue to publish writing with my favorite text editor, and I am not at all forced to use the live html editor. This is a great point, and it works very well (article on this is coming). I was not interested in comments on my blog as I do not want to host other’s comments on my personal website. But this way of using webmention incite others to have their own blog and publish on this, to reply, and I totally agree with this philosophy. This is no longer “a comment on someone’s wall that you don’t care about” but “a comment on your website which is sent to the other’s”. I think this change of commenting strategy might improve the quality of comments (but I may be wrong) by feeling more attached to your content. My demo Known instance is available <a href="http://known.phyks.me/">here</a>. It is currently to be considered as Work In Progress, and I am not sure of what it will become in the future. But there are chances I move to a full Known approach, instead of duplicating my articles on this blog and on Known. Bad news is I might have some URLs that will change in the process (old articles, photos, feeds, etc). To be continued…</p>Versionner ses fichiers de configuration avec vcsh2015-01-04T23:10:00+01:002015-01-04T23:10:00+01:00Phykstag:localhost,2015-01-04:/Blog/output/2015/01/versionner-ses-fichiers-de-configuration-avec-vcsh.html<p>Je viens de découvrir un petit outil fort pratique pour versionner ses fichiers de configuration avec Git : <a href="https://github.com/RichiH/vcsh#30-second-how-to">vcsh</a>. J’ai plusieurs ordinateurs que j’utilise régulièrement, et c’est toujours une véritable horreur de garder une configuration à jour entre les différents postes. Une solution standard est d’utiliser Git …</p><p>Je viens de découvrir un petit outil fort pratique pour versionner ses fichiers de configuration avec Git : <a href="https://github.com/RichiH/vcsh#30-second-how-to">vcsh</a>. J’ai plusieurs ordinateurs que j’utilise régulièrement, et c’est toujours une véritable horreur de garder une configuration à jour entre les différents postes. Une solution standard est d’utiliser Git, mais il faut s’amuser à faire des liens symboliques dans tous les sens si on veut pas un <code>.git</code> à la racine de son répertoire personnel, etc.</p>
<p><code>vcsh</code> sert justement à éviter ces problèmes, en vous masquant les différents dépôts utilisés. Il est ultra simple d’utilisation et remplit parfaitement son rôle.</p>
<p>Imaginons qu’on veuille versionner notre configuration de <span class="caps">ZSH</span>. Sur un des postes, il suffit de lancer <code>vcsh init zsh</code> pour démarrer un dépôt <code>zsh</code>. On ajoute ensuite nos fichiers de configuration avec <code>vcsh zsh add …</code>. Par exemple :</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>vcsh<span class="w"> </span>zsh<span class="w"> </span>add<span class="w"> </span>.zshrc<span class="w"> </span>.zprofile<span class="w"> </span>.zshenv
</code></pre></div>
<p>On peut ensuite commiter nos fichiers de configuration avec <code>vcsh zsh commit</code>. Par exemple :</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>vcsh<span class="w"> </span>zsh<span class="w"> </span>commit<span class="w"> </span>-m<span class="w"> </span><span class="s2">"Premier commit de ma config ZSH"</span>
</code></pre></div>
<p>Si on veut synchroniser ses fichiers de configuration entre plusieurs ordinateurs, il peut être utile d’ajouter un <em>remote</em> avec <code>vcsh zsh remote add origin <remote></code> puis de pusher avec <code>vcsh zsh push -u origin master</code>.</p>
<p>En gros, <code>vcsh zsh</code> remplace <code>git</code> habituellement utilisé, pour toutes les opérations de base. Vous pouvez bien sûr faire des branches, merger, pusher, puller, … sans problèmes.</p>
<p>Par exemple, pour récupérer votre configuration sur un autre ordinateur, il vous suffit de <code>vcsh clone <remote></code> et c’est reparti ! =)</p>Gestion d’articles scientifiques avec BMC2015-01-02T18:05:00+01:002015-01-02T18:05:00+01:00Phykstag:localhost,2015-01-02:/Blog/output/2015/01/gestion-darticles-scientifiques-avec-bmc.html<p>Lorsqu’on fait de la recherche scientifique (ou de la veille), on est très vite amener à stocker de très nombreux articles en PDFs. On ne s’en sert pas forcément à tous les coups, mais il est essentiel de pouvoir les retrouver et s’y référer simplement. De même …</p><p>Lorsqu’on fait de la recherche scientifique (ou de la veille), on est très vite amener à stocker de très nombreux articles en PDFs. On ne s’en sert pas forcément à tous les coups, mais il est essentiel de pouvoir les retrouver et s’y référer simplement. De même, de plus en plus d’ouvrages sont disponibles en formats numériques, et il est également utile de les stocker pour pouvoir les retrouver et les citer facilement. Bref, il faut un moyen simple de :</p>
<ul>
<li>Stocker des fichiers <span class="caps">PDF</span> et <span class="caps">DJVU</span>.</li>
<li>Les retrouver facilement.</li>
<li>Exporter des citations dans un format correct, pour pouvoir les citer au besoin (BibTeX etc.).</li>
</ul>
<p>Actuellement, je connais deux méthodes :</p>
<ol>
<li>Utiliser un logiciel tout-en-un de gestion bibliographique comme le leader du secteur, <a href="http://www.mendeley.com/">Mendeley</a>, propriétaire, qui permet d’importer ses PDFs sans y réfléchir. Il s’occupe de tout trier, de récupérer les informations dans les bases de données en ligne (auteurs, titre, revue, etc.), ce qui nécessiteraient une recherche dans le <span class="caps">PDF</span> voire de l’<span class="caps">OCR</span> autrement. On peut annoter ses documents, pour se rappeler qui est quoi, et il peut générer automatiquement les citations qui vont bien, dans le format voulu, quand on écrit un article ou un rapport. C’est top, mais c’est propriétaire et payant pour certaines fonctions avancées. Une grande partie du monde de la recherche l’utilise, mais c’est pas parfait quand même. Et c’est lourd et très (trop) complet, en cherchant à faire un réseau social autour de la recherche. Son concurrent open-source, <a href="http://zotero.org/">Zotero</a> est aussi lourd, si ce n’est plus, peu ergonomique, et pas très performant. Bref, ce n’est pas une solution idéale.</li>
<li>De l’autre côté, de nombreux chercheurs ont juste un dossier <code>~/Papers</code> et mettent tous leurs PDFs en vrac dedans. Certains tiennent un index, avec plus ou moins de succès, ou renomment les fichiers (et il faut alors garder toujours le même masque si on ne veut pas s’y perdre). C’est léger, fonctionnel, mais pas pratique. Trop contraignant à la longue. Et lorsqu’on rédige un document, on ne peut pas avoir facilement les données nécessaires pour citer l’article et on passe alors des heures sur les sites de revues pour trouver lesdites citations.</li>
</ol>
<p>Du coup, j’ai écrit un petit script sans prétention en Python qui s’occupe de toutes les étapes chronophages et insupportables de la deuxième solution : <a href="https://github.com/Phyks/BMC"><span class="caps">BMC</span></a>.</p>
<p>Le principe est très simple : on lui donne un dossier où stocker les articles (typiquement <code>~/Papers</code>) et un masque de renommage pour renommer les fichiers PDFs. Quand on veut ajouter un fichier <span class="caps">PDF</span> à sa collection, on lui dit de le faire (<code>bmc import fichier.pdf</code> ou <code>bmc download URL</code>) et il s’occupe de tout :</p>
<ul>
<li>Il va récupérer le fichier <span class="caps">PDF</span> ou djvu, si besoin</li>
<li>Il va chercher et extraire le code <span class="caps">DOI</span> (pour les articles) ou <span class="caps">ISBN</span> (pour les livres) dans le fichier</li>
<li>Grâce à ce code, il va automatiquement récupérer les données bibliographiques associées, qu’il va stocker au format <code>bibtex</code>, pour être facilement réutilisé avec <code>LaTeX</code>.</li>
<li>Finalement, il va stocker le fichier à importer dans le répertoire d’import et ajouter les données bibliographiques à un fichier d’index (<code>index.bib</code>).</li>
</ul>
<p>Comme ça, tout se fait tout seul sans qu’on y pense. Il peut utiliser d’éventuels proxy (y compris <span class="caps">SOCKS</span>) pour récupérer les articles (si vous travaillez chez vous mais que votre institution vous fournit un proxy pour télécharger des articles par exemple). Il peut aussi chercher les nouvelles versions disponibles pour les articles ajoutés (typiquement sur <a href="http://arxiv.org/">arxiv</a>, un dépôt d’articles en <a href="http://pablo.rauzy.name/openaccess/introduction.html#libre-acces">open-access</a>). Il peut aussi comparer l’état actuel de votre index et de votre répertoire de stockage, pour identifier d’éventuels problèmes (articles non ajoutés par le script ou articles mal supprimés). On peut aussi ajouter un tag sur chaque fichier, qui se retrouvera alors classé dans un sous-répertoire, pour organiser ses articles par projet.</p>
<p>Lorsque vous voulez citer un article, il vous suffit de demander à <span class="caps">BMC</span> l’entrée Bibtex correspondante (<code>bmc export ARTICLE</code>).</p>
<p>Comme il utilise des technos établies (citations Bibtex pour l’index + stockage en fichiers), il n’y a aucun risque de perdre ses données si le script n’est plus maintenu, ou n’est plus compatible. Tout sera toujours accessible, comme ce que vous auriez fait à la main. Et vous pouvez vous passer du script et aller vous-même chercher dans l’index l’entrée qui vous convient.</p>
<p>Enfin, j’espère ajouter prochainement de nouvelles fonctionnalités, selon ce qui est le plus demandé : recherche dans la base de données (qui est d’ores et déjà possible en faisant une recherche dans le fichier d’index, recherche de doublons, recherche de version publiée pour les articles en open-access, …). N’hésitez pas à me faire des retours !</p>Getting ipv6 to work with a Kimsufi server2014-11-09T19:45:00+01:002014-11-09T19:45:00+01:00Phykstag:localhost,2014-11-09:/Blog/output/2014/11/getting-ipv6-to-work-with-a-kimsufi-server.html<p>Starting from yesterday, my server (<a href="http://phyks.me">phyks.me</a>) should be available using ipv6. This was not the case before due to laziness and a lack of configuration. However, as setting ipv6 on a Kimsufi seems to not be really straight-forward (out of date documentation, information disseminated over the web and difficult …</p><p>Starting from yesterday, my server (<a href="http://phyks.me">phyks.me</a>) should be available using ipv6. This was not the case before due to laziness and a lack of configuration. However, as setting ipv6 on a Kimsufi seems to not be really straight-forward (out of date documentation, information disseminated over the web and difficult to find between basic mistakes and real errors…), I think it may be useful to keep some notes here. Hope it can help anyone.</p>
<p>The <a href="http://help.ovh.co.uk/Ipv4Ipv6">doc</a> explains that <span class="caps">OVH</span> has not set ipv6 autoconfig on their servers, and that you should configure the default route and <span class="caps">IP</span> address yourself.</p>
<p>To find your ip address, it is pretty easy: just go to your manager and look for the ipv6 address in the <span class="caps">IP</span> section.</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>ip<span class="w"> </span>-6<span class="w"> </span>addr<span class="w"> </span>add<span class="w"> </span>YOUR_IPV6_ADDRESS/64<span class="w"> </span>dev<span class="w"> </span>eth0
</code></pre></div>
<p>This will add the ipv6 address to your network device. Then, you have to manually add the default gateway. To get its address, you should remove the last two digits of your ipv6 address and put <code>FF:FF:FF:FF:FF</code> instead. This means that <code>2001:41d0:1:4462::1/64</code> will give you a default gateway <code>2001:41d0:1:44FF:FF:FF:FF:FF</code>.</p>
<p>Then, you should add a default route <em>via</em> this gateway</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>ip<span class="w"> </span>-6<span class="w"> </span>r<span class="w"> </span>a<span class="w"> </span>default<span class="w"> </span>via<span class="w"> </span><span class="m">2001</span>:41d0:1:44FF:FF:FF:FF:FF
</code></pre></div>
<p>This is the standard procedure explained in <span class="caps">OVH</span> guide and many posts around the web such as <a href="https://www.skyminds.net/serveur-dedie-mise-en-place-de-lipv6/">this one</a> (in French). It may work in some cases, however, in my case, I could not reach the default gateway and then, I could not add this route.</p>
<p>I found <a href="http://forum.ovh.co.uk/showthread.php?6435-Getting-IPv6-working-on-kimsufi&p=44965&viewfull=1#post44965">a comment</a> on the <span class="caps">OVH</span> forum giving a solution.</p>
<p>You should first add a route to reach the gateway</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>ip<span class="w"> </span>-6<span class="w"> </span>r<span class="w"> </span>a<span class="w"> </span><span class="m">2001</span>:41d0:1:44FF:FF:FF:FF:FF<span class="w"> </span>dev<span class="w"> </span>eth0
</code></pre></div>
<p>and then, you can add the default route <em>via</em> this gateway</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>ip<span class="w"> </span>-6<span class="w"> </span>r<span class="w"> </span>a<span class="w"> </span>default<span class="w"> </span>via<span class="w"> </span><span class="m">2001</span>:41d0:1:44FF:FF:FF:FF:FF
</code></pre></div>Proof-of-concept: BloomySearch, a (JavaScript) client-side search engine for static websites2014-11-08T18:45:00+01:002014-11-08T18:45:00+01:00Phykstag:localhost,2014-11-08:/Blog/output/2014/11/proof-of-concept-bloomysearch-a-javascript-client-side-search-engine-for-static-websites.html<h2>Overview</h2>
<p>Many websites and blogs are statically generated and the webserver only serves static files. It is the case of many doc websites and more and more blogs, starting from this one, as <a href="http://jekyllrb.com/">Jekyll</a> / <a href="http://blog.getpelican.com/">Pelican</a> develops.</p>
<p>This is really useful to reduce the complexity of the website and the load …</p><h2>Overview</h2>
<p>Many websites and blogs are statically generated and the webserver only serves static files. It is the case of many doc websites and more and more blogs, starting from this one, as <a href="http://jekyllrb.com/">Jekyll</a> / <a href="http://blog.getpelican.com/">Pelican</a> develops.</p>
<p>This is really useful to reduce the complexity of the website and the load on the webserver. All the complex logic is done at the generation.</p>
<p>However, this also means you do not have dynamic pages on your website to handle search queries. Then, you are left with two (or three) choices :</p>
<ol>
<li>Use an external search engine, such as an embedded Google search box. This raises some privacy concerns and make you depends on an external service.</li>
<li>(Use a <span class="caps">JS</span> search engine such as the <a href="http://www.airpair.com/angularjs#/10-filters-core-">filters</a> provided by Angular.<span class="caps">JS</span>. This only works on the displayed content, and is not a real solution).</li>
<li>Stop worrying about search engine on your website and let the users <code>wget</code>-ing and <code>grep</code>-ing your website on their computers. This is not the most user-friendly solution…</li>
</ol>
<p>There are a couple of solutions around, mostly based on <a href="http://lunrjs.com/">Lunr.js</a> which generates an index from the articles available, and use this index for fulltext search. This is the best solution I found so far but it is still not perfect. Although there is a stemmer and an index generation to reduce the amount of data to be transferred, the data is not stored in a very efficient way, and the full index is sent as <span class="caps">JSON</span>. An example implementation for Jekyll is available through <a href="https://github.com/slashdotdash/jekyll-lunr-js-search">the jekyll-lunr-js-search plugin</a>.</p>
<p>I had the idea of a client side search engine in mind for a while, but was facing the same problem as Lunr.js: how not to send a full (very large) index over the network to every single client ? Not having an optimized data structure would basically mean sending twice the content of the website to the client. It may not be a practical problem nowadays, as transfer speed is not always the limiting resource, but it is still not to be considered as a good practice, in my opinion, especially if your website might be accessed from mobile devices.</p>
<p>I came accross <a href="http://www.stavros.io/posts/bloom-filter-search-engine/?print">this article</a> from Stavros Korokithakis and thought something similar could be achieved directly in the browser. Instead of using a standard dictionary to store the index, this article proposes to use a Bloom filter per article. Bloom filters are very interesting probabilistic structures which can store whether an element is or not in a set, with a fixed number of bits. It can return false positives: if an element is in the set, it always returns <code>True</code>, but if an element is not in the set, it may say it is actually in, with a small probability. <a href="https://en.wikipedia.org/wiki/Bloom_filter">Wikipedia page</a> on the subject has all the necessary stuff to understand these data structures.</p>
<p>I wrote it in the context of my blog, which means a Python script to generate the index at pages generation, and a client side search engine in JavaScript, running in browser.</p>
<p>A demo is available <a href="https://phyks.github.io/BloomySearch/">here</a>. It contains all the articles of my blog, as of writing this article, totalizing 160k characters, and only 7kB of index, allowing 10% of false positives, which may be a bit too much for a really reliable search engine. Reducing the error rate will lead to an increase in the index size (11kB for 1% of false positives and the same amount of characters).</p>
<h2>Details of the implementation</h2>
<p>As JavaScript is not the easier language to use for hashing and binary data manipulation, I started by implementing the client side search engine. Then, it would be easier to adapt the Python code to the <span class="caps">JS</span> lib than doing the contrary. Actually, I found <a href="https://github.com/jasondavies/bloomfilter.js">this bloomfilters.js library</a> from Jason Davies which was doing most of the job and did not need many modifications. I edited it a bit to support a construction with a <code>capacity</code> and an <code>error_rate</code>, instead of an explicit number of bits and times to apply the hashing function. This forked version is available <a href="https://github.com/Phyks/bloomfilter.js/blob/master/bloomfilter.js">here</a>.</p>
<p>Then, I reimplemented this library in Python, to generate readable Bloom filters for the JavaScript script.</p>
<h3>Server side</h3>
<p>The generation script takes every articles in a given directory and for each of them:</p>
<ol>
<li>It gets a set of all the words in this article, ignoring too short words.</li>
<li>It applies <a href="http://tartarus.org/martin/PorterStemmer/">Porter Stemming Algorithm</a> to reduce drastically the number of words to keep.</li>
<li>It generates a Bloom filters containing all of these words.</li>
</ol>
<p>Finally, it concatenates all the per article Bloom filters in a binary file, to be sent to the client. It also generates a <span class="caps">JSON</span> index mapping the id of the Bloom filter in the binary file to the corresponding <span class="caps">URL</span> and title for each article.</p>
<h3>Client side</h3>
<p>Upon loading, the JavaScript script downloads the binary file (see <a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data">this <span class="caps">MDN</span> doc</a> for more details) containing the Bloom filters and the <span class="caps">JSON</span> index, and regenerate BloomFilters on the client side.</p>
<p>When the client searches for something, the JavaScript script splits the query in words and iterate over the Bloom filters to search for the words. That’s it =)</p>
<h2>(Fun) facts found while reimplementing the Bloom filters library in Python</h2>
<p>First problem I had to deal with : the difference between JavaScript <code>Number</code> type and Python <code>int</code>. JavaScript has only one type for all numbers (<code>int</code> or <code>floats</code>) and it is <code>Number</code> (see <a href="https://stackoverflow.com/questions/307179/what-is-javascripts-highest-integer-value-that-a-number-can-go-to-without-losin">this <span class="caps">SO</span> thread</a>). They are 64-bit floating point values, with a magnitude no greater than 2<sup>53</sup>. However, when doing bitwise operations, they are casted to 32 bits before doing the operation. This is something to take care of, because Python’s <code>int</code> can be 64 bits (<a href="http://legacy.python.org/dev/peps/pep-0237/">http://legacy.python.org/dev/peps/pep-0237/</a>). Then, when a bitwise operation overflows in JavaScript, it may not overflow the same way in Python.</p>
<p>The solution to this problem was to use <code>ctypes.c_int</code> in Python for bitwise operations, as proposed <a href="https://stackoverflow.com/questions/1694507/difference-between-operator-in-js-and-python">here</a>.</p>
<p>Another problem was the difference between modulo behaviour with negative numbers in Python and in JavaScript. Unlike C, C++ and JavaScript, Python’s modulo operator (%) always return a number having the same sign as the divisor (<a href="https://stackoverflow.com/questions/3883004/negative-numbers-modulo-in-python">Source</a>). Then, we have to reimplement the C behaviour in a modulo function in Python.</p>
<p>Finally, there was no “shift right adding zeros” (logical right shift) in Python, contrary to <span class="caps">JS</span>, see <a href="https://stackoverflow.com/questions/5832982/how-to-get-the-logical-right-binary-shift-in-python">this <span class="caps">SO</span> thread</a>.</p>Balancer le son de ses hauts-parleurs sur le réseau2014-10-26T22:40:00+01:002014-10-26T22:40:00+01:00Phykstag:localhost,2014-10-26:/Blog/output/2014/10/balancer-le-son-de-ses-hauts-parleurs-sur-le-reseau.html<p>J’ai un <span class="caps">PC</span> fixe et un portable, et je cherchais un moyen de balancer le son de mon portable sur les hauts-parleurs de bonne qualité branchés sur mon <span class="caps">PC</span> fixe, quand je suis sur le même réseau. Et en fait, c’est très simple à faire avec PulseAudio.</p>
<h2>La …</h2><p>J’ai un <span class="caps">PC</span> fixe et un portable, et je cherchais un moyen de balancer le son de mon portable sur les hauts-parleurs de bonne qualité branchés sur mon <span class="caps">PC</span> fixe, quand je suis sur le même réseau. Et en fait, c’est très simple à faire avec PulseAudio.</p>
<h2>La première méthode, simple, qui marche partout</h2>
<p>S’assurer d’avoir <code>pulseaudio</code> configuré sur ses ordinateurs, et installer <code>paprefs</code>. Lancer <code>paprefs</code> et dans l’onglet <code>Multicast/RTP</code>, cocher la case <em>receiver</em> sur le <span class="caps">PC</span> sur lequel les hauts-parleurs sont branchés, et la case <em>sender</em> sur l’autre.</p>
<p>Sur le <span class="caps">PC</span> qui envoie la musique (<em>sender</em>), vous avez le choix entre trois options, dont seulement deux nous intéressent : <code>Send audio from local speakers</code> (qui enverra tout le son local sur les hauts-parleurs distants) et <code>Create separate audio device for Multicast/RTP</code> (qui vous rajoutera une sortie son <code>Multicast/RTP</code> que vous pourrez utiliser ou non, par application).</p>
<p>Si vous n’avez pas de pare-feu et que vous êtes bien sur le même réseau, c’est tout ce que vous avez à faire !</p>
<p>Par contre, vous remarquerez vite que la qualité n’est pas top (au moins chez moi) : un bon <span class="caps">FLAC</span> d’un côté ressort vite comme un <span class="caps">MP3</span> 64k d’il y a quelques années de l’autre côté…</p>
<h2>La deuxième solution, encore plus simple, qui marche mieux !</h2>
<p>La deuxième solution consiste à utiliser les deux premiers onglets de <code>paprefs</code> : <code>Network Access</code> et <code>Network Server</code>.</p>
<p>Sur le <span class="caps">PC</span> qui envoie le son, cochez la case <code>Make discoverable PulseAudio network sound devices available locally</code> dans le premier onglet.</p>
<p>Sur le <span class="caps">PC</span> qui reçoit le son, cochez les trois premières cases (<code>Activer l'accès réseau aux périphériques de son locaux</code>).</p>
<p>Et c’est tout =) Vous aurez désormais les sorties audio de votre autre <span class="caps">PC</span> qui apparaîtront chez vous (par exemple dans <code>Audio -> Périphérique audio</code> dans <span class="caps">VLC</span>). Et pour le coup, plus aucun problème de qualité à signaler ! Testé en filaire, et aucun problème de débit / lag / son à signaler pour l’instant.</p>
<p>À noter cependant que chez moi, j’ai deux sorties qui sont disponibles, une appelée <code>Audio interne…</code> et l’autre appelée <code>Simultaneous output to Audio interne…</code>. Si j’utilise la deuxième, j’ai le son qui saute, et c’est inutilisable, mais la première fonctionne nickel.</p>
<h2>Références</h2>
<p>Principalement un seul lien : <a href="http://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Network/#index2h3">http://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Network/#index2h3</a>. Mais ils font tout à coup de ligne de commande et c’est en fait bien plus simple de passer par paprefs.</p>Utiliser son PC sous Arch pour connecter un Raspberry Pi à Internet2014-10-18T22:40:00+02:002014-10-18T22:40:00+02:00Phykstag:localhost,2014-10-18:/Blog/output/2014/10/utiliser-son-pc-sous-arch-pour-connecter-un-raspberry-pi-a-internet.html<p>J’ai un Raspberry Pi et mon portable sous Arch Linux, et je me promène pas mal avec les deux. Mais je n’ai pas toujours de routeur à disposition pour brancher les deux sur le même réseau et travailler facilement. Il est très simple de mettre en place en …</p><p>J’ai un Raspberry Pi et mon portable sous Arch Linux, et je me promène pas mal avec les deux. Mais je n’ai pas toujours de routeur à disposition pour brancher les deux sur le même réseau et travailler facilement. Il est très simple de mettre en place en 5 minutes une configuration me permettant de connecter le Raspberry Pi sur mon portable, et de partager la connexion Internet issue du wifi de mon <span class="caps">PC</span> avec le Raspberry Pi. Comme ça, plus de problèmes, je peux bosser sur le Raspberry Pi n’importe où.</p>
<p>C’est parti !</p>
<p><em>Note</em> : J’utilise cette configuration pour développer, et elle n’est donc pas forcément optimale et devrait sûrement être adaptée pour être utilisée en production.</p>
<h2>Installation d’un serveur dhcp sur le portable</h2>
<p>Commençons par installer un serveur dhcp sur le <span class="caps">PC</span> avec Arch, pour éviter de devoir saisir une adresse <span class="caps">IP</span> fixe sur le Raspberry Pi. Comme ça, on peut utiliser n’importe quelle image sans réfléchir, comme si on avait un routeur qui va bien.</p>
<p>Le plus simple est de suivre <a href="https://wiki.archlinux.org/index.php/Dhcpd">cette page de la documentation</a>.</p>
<ol>
<li>On attribue une adresse <span class="caps">IP</span> fixe à l’interface ethernet (ici 192.168.192.1, attention à ce que ça ne rentre pas en conflit avec votre configuration réseau).</li>
</ol>
<div class="highlight"><pre><span></span><code>ip<span class="w"> </span>link<span class="w"> </span><span class="nb">set</span><span class="w"> </span>up<span class="w"> </span>dev<span class="w"> </span>enp4s0f2
ip<span class="w"> </span>addr<span class="w"> </span>add<span class="w"> </span><span class="m">192</span>.168.192.1/24<span class="w"> </span>dev<span class="w"> </span>enp4s0f2
</code></pre></div>
<ol>
<li>
<p>Déplacer le fichier <code>/etc/dhcpd.conf</code> fourni par défaut vers <code>/etc/dhcpd.conf.example</code> pour pouvoir le modifier sereinement.</p>
</li>
<li>
<p>Éditer le fichier <code>/etc/dhcpd.conf</code>. À titre indicatif, voici le mien :</p>
</li>
</ol>
<div class="highlight"><pre><span></span><code>option domain-name-servers 8.8.8.8, 8.8.4.4;
option subnet-mask 255.255.255.0;
option routers 192.168.192.1;
subnet 192.168.192.0 netmask 255.255.255.0 {
range 192.168.192.10 192.168.192.20;
}
</code></pre></div>
<p>Je spécifie d’utiliser les serveurs <span class="caps">DNS</span> de Google (qui sont disponibles partout -si vous avez un serveur sur votre ordinateur, vous pouvez le mettre à la place), que le routeur est à l’adresse <code>192.168.192.1</code> et que j’attribue des adresses dans la gamme <code>192.168.192.10-192.168.192.20</code>.</p>
<ol>
<li>Vous pouvez lancer le service dhcpd avec <code>systemctl start dhcpd4</code>. Je préfèrais restreindre l’interface sur laquelle le serveur <span class="caps">DHCP</span> tournait, pour ne l’utiliser que sur l’interface ethernet. Pour se faire, il suffit de suivre les instructions « Listening on only one interface - Service file » de la <a href="https://wiki.archlinux.org/index.php/Dhcpd">documentation Arch Linux</a>.</li>
</ol>
<h2>Configuration du pare-feu et du noyau</h2>
<p>Il faut ensuite configurer <code>iptables</code> et le noyau pour rediriger les paquets réseau vers le Raspberry Pi.</p>
<p>Pour ce faire,</p>
<div class="highlight"><pre><span></span><code>iptables<span class="w"> </span>-A<span class="w"> </span>FORWARD<span class="w"> </span>-o<span class="w"> </span>wlp3s0<span class="w"> </span>-i<span class="w"> </span>enp4s0f2<span class="w"> </span>-s<span class="w"> </span><span class="m">192</span>.168.192.1/24<span class="w"> </span>-m<span class="w"> </span>conntrack<span class="w"> </span>--ctstate<span class="w"> </span>NEW<span class="w"> </span>-j<span class="w"> </span>ACCEPT
iptables<span class="w"> </span>-A<span class="w"> </span>FORWARD<span class="w"> </span>-m<span class="w"> </span>conntrack<span class="w"> </span>--ctstate<span class="w"> </span>ESTABLISHED,RELATED<span class="w"> </span>-j<span class="w"> </span>ACCEPT
iptables<span class="w"> </span>-A<span class="w"> </span>POSTROUTING<span class="w"> </span>-t<span class="w"> </span>nat<span class="w"> </span>-j<span class="w"> </span>MASQUERADE
</code></pre></div>
<p>et on dit active le <em>forwarding</em> dans le noyau :</p>
<div class="highlight"><pre><span></span><code><span class="nb">echo</span><span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>tee<span class="w"> </span>/proc/sys/net/ipv4/ip_forward
</code></pre></div>
<h2>Le script qui va bien</h2>
<p>Une fois le serveur <code>dhcpd</code> configuré, <a href="https://pub.phyks.me/scripts/dhcp_server.sh">ce script</a> permet de tout démarrer / arrêter.</p>
<p>Attention, le <em>flush</em> dans la fonction <code>stop</code> peut être trop brutal pour vous.</p>Synchroniser ses ordinateurs 1/22014-08-07T22:30:00+02:002014-08-07T22:30:00+02:00Phykstag:localhost,2014-08-07:/Blog/output/2014/08/synchroniser-ses-ordinateurs-12.html<h2>Étude des solutions disponibles</h2>
<p>J’utilise quotidiennement au moins 2 ordinateurs : mon ordinateur portable et mon fixe. Tous les deux ont des gros disques durs (> 1 To) et je cherche depuis quelques temps à les synchroniser pour les utiliser de façon totalement transparente avec mes fichiers (et avec la configuration …</p><h2>Étude des solutions disponibles</h2>
<p>J’utilise quotidiennement au moins 2 ordinateurs : mon ordinateur portable et mon fixe. Tous les deux ont des gros disques durs (> 1 To) et je cherche depuis quelques temps à les synchroniser pour les utiliser de façon totalement transparente avec mes fichiers (et avec la configuration utilisateur de base, tel que mon <code>.vimrc</code>, mon thème pour <code>rxvt-unicode</code>, etc.).</p>
<p>J’ai également un gros disque dur externe, sur lequel je veux faire des <em>backups</em> complets réguliers de certains fichiers.</p>
<p>Je dois donc maintenir en permanence 3 disques durs synchronisés : celui de mon ordinateur fixe, de mon portable et mon disque dur externe. Faire ça à la main, c’est très long et fastidieux (et potentiellement compliqué). Je cherche donc un moyen d’automatiser tout ça proprement. De plus, j’ai un serveur dédié, avec de l’espace disque disponible, sur lequel je voudrais stocker une partie des sauvegardes, pour avoir un <em>backup</em> décentralisé en cas de pépin.</p>
<p>Les solutions à envisager doivent répondre aux critères suivants :</p>
<ul>
<li>Pouvoir facilement choisir les dossiers et les fichiers à synchroniser et être capable de synchroniser de gros fichiers sans problèmes et dans des temps décents. Je veux synchroniser tout mon <em>home</em> entre mes deux ordinateurs et mon disque dur externe, mais je ne veux pas synchroniser toutes mes musiques et vidéos avec mon serveur, pour ne pas le saturer inutilement. J’ai pas mal de scripts déjà versionnés par Git également, que je veux pouvoir exclure facilement.</li>
<li>Proposer une solution de sauvegarde chiffrée (transferts chiffrés entre les postes et chiffrement de mes données sur mes serveurs).</li>
<li>Permettre une architecture décentralisée, pas besoin de repasser par mon serveur pour synchroniser mes postes quand ils sont sur le même réseau local.</li>
</ul>
<p>J’ai également repéré trois solutions potentielles : <a href="http://www.cis.upenn.edu/~bcpierce/unison/">Unison</a>, <a href="http://syncthing.net/">Syncthing</a> trouvé grâce à <a href="http://tomcanac.com/blog/2014/07/14/syncthing-alternative-libre-btsync/">cet article de tmos</a> et <a href="http://git-annex.branchable.com/">git-annex</a> trouvé par <a href="http://flo.fourcot.fr/index.php?post/2013/07/19/J-ai-d%C3%A9couvert-git-annex">cet article</a>. (Je cherche bien sûr une solution <em>opensource</em> à installer sur mon serveur)</p>
<h3>Unison</h3>
<p><a href="http://www.cis.upenn.edu/~bcpierce/unison/">Unison</a> est un programme de synchronisation de fichier multiplateforme, écrit en Ocaml. Il gère les conflits automatiquement si possible, et avec intervention de l’utilisateur si besoin. Il prend un grand soin à laisser les systèmes en état fonctionnel à chaque instant, pour pouvoir récupérer facilement en cas de problèmes. Par contre, le projet était un projet de recherche initialement, et avait donc un développement très actif. Ce n’est plus le cas, et le développement est beaucoup moins actif, comme expliqué <a href="http://www.seas.upenn.edu/~bcpierce/unison//status.html">sur la page du projet</a>.</p>
<p>Autre limitation : il n’est possible de synchroniser que des <em>paires</em> de machines avec Unison. Cela veut dire que pour synchroniser mes 3 machines, je vais devoir utiliser une configuration en étoiles, en passant forcément par mon serveur. C’est pas top car mon portable et mon ordinateur fixe étant très souvent sur le même réseau, il peut être intéressant de s’affranchir du serveur dans ce cas, pour avoir des taux de transfert plus élevés.</p>
<p>Enfin, il semble assez non trivial d’avoir un chiffrement des données synchronisées, et ce n’est pas implémenté directement par Unison. Il faut donc rajouter une couche d’Encfs ou autre. <a href="https://bbs.archlinux.org/viewtopic.php?pid=1317177#p1317177">Une discussion sur le forum archlinux</a> (en anglais) évoque cette possibilité, et <a href="http://www.mail-archive.com/encfs-users@lists.sourceforge.net/msg00164.html">un post</a> sur la mailing-list [Encfs-users] donne quelques détails supplémentaires.</p>
<h3>Syncthing</h3>
<p>(Je reprends les informations du <a href="http://syncthing.net/">site officiel</a> et de <a href="http://tomcanac.com/blog/2014/07/14/syncthing-alternative-libre-btsync/">l’article de Tom</a>.)</p>
<p>Syncthing est écrit en Go. Toutes les communications sont chiffrées par <span class="caps">TLS</span> et chaque nœud est authentifié et doit être explicitement ajouté pour pouvoir accéder aux fichiers. Syncthing utilise donc son propre protocole, et sa propre authentification. Il est multiplateforme, a une très jolie interface et ne requiert aucune configuration particulière (il est censé fonctionner <em>out of the box</em>, en utilisant uPnP si besoin pour ne pas avoir besoin de mettre en place de translation de port).</p>
<p>Chaque machine peut échanger avec toutes les machines avec lesquelles il y a eu un échange d’identifiants. On peut donc très facilement choisir de construire une architecture centralisée ou décentralisée (dans le premier cas, toutes les machines n’auront que l’identifiant du serveur central, dans le deuxième cas toutes les machines auront les identifiants de toutes les autres).</p>
<p>Toute la configuration se fait par une jolie interface web, protégée par mot de passe. Vous pouvez partager chaque dossier comme bon vous semble, et vous pouvez même partager certains dossiers avec des personnes extérieures, à la dropbox, sans dropbox :). Et de par l’architecture du logiciel, il n’y a pas de <em>serveur</em> ni de <em>client</em> mais un seul logiciel qui tourne partout.</p>
<p><img alt="La jolie interface de Syncthing" src="http://localhost/Blog/output/images/2014/08/syncthing.png"></p>
<p>Le code est disponible sur <a href="https://github.com/syncthing/syncthing">Github</a>, le dépôt est actif et les tags sont signés.</p>
<p>Il satisfait donc a priori la plupart de mes besoins. Il faut juste que je trouve un moyen de chiffrer mes documents sur mon serveur (mes disques sont déjà chiffrés, mais je voudrais avoir un gros conteneur déchiffré à chaque synchronisation, et verrouillé après idéalement). Apparemment, c’est <a href="https://github.com/syncthing/syncthing/issues/109">en cours de discussion</a>.</p>
<p>Concernant la gestion des conflits, elle n’a pas l’air parfaite, comme le montre <a href="https://github.com/syncthing/syncthing/issues/220">cette <em>issue</em></a> sur Github. Il semblerait que la politique actuelle soit <em>newest wins</em> ce qui peut causer des pertes de données (une copie de sauvegarde est peut être réalisée, car SyncThing peut versionner les fichiers, mais je ne suis pas sûr de ce point, à tester).</p>
<h3>Git-annex</h3>
<p><a href="http://git-annex.branchable.com/">Git-annex</a> est un programme permettant de synchroniser ses fichiers en utilisant Git. En fait, il est vu comme un plugin pour Git, et il va stocker les fichiers dans un dépôt Git, mais ne pas versionner leur contenu. Du coup, on évite de devoir versionner des gros fichiers et donc les problèmes habituels de Git avec des gros fichiers potentiellement binaires.</p>
<p>C’est certainement le programme le plus abouti des trois présentés ici, son développement est actif, il y a une communauté derrière (et du monde sur <span class="caps">IRC</span> !) et le développeur a réussi une campagne Kickstarter l’an dernier pour se financer pour travailler sur le logiciel pendant un an. Il a notamment implémenté un assistant web dernièrement, permettant de gérer ses synchronisations <em>via</em> une interface web fort jolie à la Syncthing, en s’affranchissant de la ligne de commande. Je pense quand même que Syncthing est plus <em>user friendly</em>.</p>
<p>Les possibilités du logiciel, listées sur <a href="http://git-annex.branchable.com">la page du projet</a> sont assez impressionnantes. Parmi les fonctionnalités avancées :</p>
<ul>
<li>
<p>Possibilité d’avoir tous les fichiers listés partout, même si leur contenu n’est pas effectivement présent sur le disque. Du coup, git-annex sait où aller chercher chaque fichier pour nous aider à nous y retrouver avec plusieurs supports de stockage (plusieurs disques durs externes de <em>backup</em> par exemple)</p>
</li>
<li>
<p>Git-annex utilise des dépôts standards, ce qui permet d’avoir un dépôt toujours utilisable, même si Git et Git-annex tombent dans l’oubli.</p>
</li>
<li>
<p>Il peut gérer autant de clones qu’on veut, et peut donc servir à synchroniser selon l’architecture qu’on veut. Il est capable d’attribuer des poids différents à chaque source, ce qui veut dire que je peux synchroniser mes ordinateurs <em>via</em> mon serveur, et si jamais ils sont sur le même réseau local, je peux synchroniser directement sans passer par mon serveur.</p>
</li>
<li>
<p>Il gère plusieurs possibilités de chiffrement, pour chiffrer les copies distantes, sur mon serveur par exemple. Et il permet de chiffrer tout en partageant entre plusieurs utilisateurs. Il peut utiliser d’office un serveur distant tel qu’un serveur sur lequel on a un accès <span class="caps">SSH</span> (et les transferts sont immédiatement chiffrés par <span class="caps">SSH</span> du coup) ou encore un serveur Amazon S3.</p>
</li>
<li>
<p>Possibilité de partager des fichiers avec des amis en utilisant un serveur tampon. Ce serveur stocke uniquement les fichiers en cours de transfert et n’a donc pas besoin d’un espace disque considérable.</p>
</li>
<li>
<p>Il gère les conflits.</p>
</li>
<li>
<p>Il peut utiliser des <em>patterns</em> pour exclure des fichiers, ou les inclure au contraire. On peut faire des requêtes complètes telles que “que les <span class="caps">MP3</span> et les fichiers de moins de N Mo”.</p>
</li>
<li>
<p>Bonus : il peut être utilisé pour servir un dossier semblable à mon <a href="http://pub.phyks.me">pub.phyks.me</a>, que j’implémenterai sûrement du coup, pour permettre de cloner tout mon <code>pub</code> directement.</p>
</li>
</ul>
<p>Plusieurs <em>screencasts</em> sont disponibles dans la <a href="http://git-annex.branchable.com/assistant/">documentation</a> et un retour en français est disponible <a href="http://flo.fourcot.fr/index.php?post/2013/07/19/J-ai-d%C3%A9couvert-git-annex">ici</a>.</p>
<p>Ses points forts ont vraiment l’air d’être ses fonctions avancées et la possibilité de gérer finement la localisation des fichiers. Git-annex ne se contente pas de vous permettre de synchroniser des fichiers, mais aussi de les déplacer géographiquement, partager et sauvegarder.</p>
<h2>Conclusion (temporaire)</h2>
<p>J’ai repéré trois solutions envisageables pour l’instant : Unison, SyncThing et git-annex, par ordre de fonctionnalités. Les informations précédentes sont uniquement issues des articles, documentations et retours d’utilisateurs. SyncThing a l’air le plus <em>user friendly</em> de tous, et il a des fonctionnalités intéressantes et avancées. git-annex est clairement celui qui a le plus de fonctionnalités, mais il est donc également plus compliqué à prendre en main.</p>
<p>Après cette analyse, je pense donc partir sur git-annex pour mettre en place mes sauvegardes. Rendez-vous bientôt pour la deuxième partie de cet article, avec un retour complet sur ma procédure de synchronisation (dans quelques temps quand même… faut que je réfléchisse à mon truc et que je dompte git-annex =).</p>
<h2>Notes</h2>
<ul>
<li>
<p>Après réflexion, utiliser le disque dur externe en plus fait beaucoup de redondance. Du coup, si je ne peux synchroniser qu’une partie de mes fichiers sur celui-ci, c’est encore mieux (par exemple que ma bibliothèque de musiques / films).</p>
</li>
<li>
<p>Une autre solution qui pourrait vous intéresser est <a href="https://tahoe-lafs.org/trac/tahoe-lafs">Tahoe-<span class="caps">LAFS</span></a> qui distribue vos fichiers sur plusieurs serveurs de sorte qu’aucun serveur ne puisse connaître vos données, et que si un serveur est en panne, vous puissiez toujours les récupérer (par défaut il utilise 10 nœuds pour le stockage et ne nécessite que 3 nœuds pour reconstituer les données, si j’ai bien compris). Voir aussi <a href="http://numaparis.ubicast.tv/videos/rozofs/">cette vidéo sur rozoFS</a> à <span class="caps">PSES</span> 2014, pour avoir une idée de comment cela fonctionne.</p>
</li>
<li>
<p>Un <code>rsync</code> basique ne me suffit pas, car je dois pouvoir gérer des modifications des deux côtés de la connexion à la fois, et pouvoir gérer les conflits.</p>
</li>
</ul>Recevoir ses emails par SMS avec Free Mobile2014-07-30T15:00:00+02:002014-07-30T15:00:00+02:00Phykstag:localhost,2014-07-30:/Blog/output/2014/07/recevoir-ses-emails-par-sms-avec-free-mobile.html<p><em>Edit</em> : Cela fait bientôt une semaine que l’<span class="caps">API</span> Free me renvoie un 402, en boucle… je ne peux plus envoyer de <span class="caps">SMS</span> depuis l’<span class="caps">API</span>. Je ne sais pas combien de temps ça va durer, à suivre… mais du coup c’était pas forcément une super idée… soyez prévenus …</p><p><em>Edit</em> : Cela fait bientôt une semaine que l’<span class="caps">API</span> Free me renvoie un 402, en boucle… je ne peux plus envoyer de <span class="caps">SMS</span> depuis l’<span class="caps">API</span>. Je ne sais pas combien de temps ça va durer, à suivre… mais du coup c’était pas forcément une super idée… soyez prévenus ! :)</p>
<p>Si vous êtes client Free Mobile (forfait à 2€ ou à 19€), sachez que Free met à disposition gratuitement une <a href="http://www.freenews.fr/spip.php?article14817"><span class="caps">API</span> d’envoi de <span class="caps">SMS</span></a>. <em>Via</em> un appel <span class="caps">HTTP</span>, vous pourrez désormais vous envoyer des notifications par <span class="caps">SMS</span> (uniquement à destination de votre numéro donc), ce qui fait le plus grand bonheur des utilisateurs de solutions domotiques.</p>
<p>Dans cet article, je vais l’utiliser dans un but différent : recevoir mes emails par <span class="caps">SMS</span>. Je pars d’ici peu pour une semaine à l’étranger (pas de connexion internet…) et ai besoin de relever mes emails régulièrement. Grâce à ce service, je vais pouvoir les recevoir par <span class="caps">SMS</span>.</p>
<p><em>Note</em> : Recevoir ses emails par <span class="caps">SMS</span> peut poser des problèmes de vie privée, votre opérateur voyant passer tous vos <span class="caps">SMS</span> notamment. Ça peut être d’autant plus gênant si vous recevez des rappels de mot de passe par email, qui vous seront transmis par <span class="caps">SMS</span>.</p>
<p>Je me suis grandement inspiré de <a href="http://louis.jachiet.com/blog/?p=228">cet article</a> mais ai réécrit le script. Le script ci-dessous est donc en Python (que je maîtrise mieux que Perl), gère plusieurs serveurs et se connecte en <span class="caps">IMAP</span> à vos boîtes, pour pouvoir récupérer des emails chez Gmail and cie, pour lesquels on ne peut pas mettre de règles <code>procmail</code>. Dans mon script, les identifiants / mots de passe sont en clair pour pouvoir l’éxecuter <em>via</em> une <code>crontask</code>. Si vous ne contrôlez pas le serveur sur lequel vous faites tourner ce script ou ne réglez pas correctement les permissions, attention à vos mots de passe !</p>
<p>Première étape, il faut aller activer l’option sur votre compte. Sur le site de Free, Gérer mon compte → Mes Options → Notifications par <span class="caps">SMS</span> → Activer. Vous pourrez alors récupérer votre clé d’<span class="caps">API</span>.</p>
<p>Deuxième étape, récupérer <a href="https://github.com/Phyks/Emails_SMS_Free_Mobile_API">ce script</a> qui va vous permettre de vous connecter à vos boîtes <span class="caps">IMAP</span>.</p>
<p>Troisième étape, éditer le script pour correspondre à vos besoins. Tous les paramètres à modifier sont entre des commentaires <code># EDIT BELOW ACCORDING TO YOUR NEEDS</code> et <code># YOU SHOULD NOT HAVE TO EDIT BELOW</code>. Il vous faudra ajouter vos serveurs <span class="caps">IMAP</span> (serveur, login et mot de passe, et boîte à utiliser (par-défaut, <span class="caps">INBOX</span>)). Vous pouvez ajouter autant de serveurs que vous voulez en dupliquant les dictionnaires au sein de la liste <code>imap_servers</code>. Il vous faudra également éditer votre login pour l’<span class="caps">API</span> (<code>IDENT</code>, identifiant de connexion au compte) et la clé d’<span class="caps">API</span> à utiliser (<code>PASS</code>).</p>
<p><em>Note</em>: L’<span class="caps">URL</span> ne devrait pas avoir besoin d’être modifiée, et <code>save_path</code> est le fichier <span class="caps">JSON</span> utilisé pour stocker les identifiants des emails relevés (et uniquement les identifiants), pour ne pas renvoyer la même notification plusieurs fois.</p>
<p>Finalement, il ne reste plus qu’à mettre ce script sur un de vos serveurs (ou une machine allumée suffisamment souvent), et à le lancer <em>via</em> une <code>crontask</code>, par exemple <code>*/15 * * * * python3 ./mails_sms_free.py > .mails_sms_free.log</code> pour relever vos emails toutes les 15 minutes.</p>
<p><em>Note</em> : J’utilise ce script depuis une journée sans problèmes, mais il est sûrement imparfait. N’hésitez pas à <a href="https://phyks.me/">me signaler</a> (ou <em>via</em> les <em>issues</em> Github) d’éventuels problèmes rencontrés.</p>Lister des corrections en ligne2014-07-24T22:35:00+02:002014-07-24T22:35:00+02:00Phykstag:localhost,2014-07-24:/Blog/output/2014/07/lister-des-corrections-en-ligne.html<p>Il m’arrive souvent de corriger des documents textes et de devoir noter
facilement les fautes d’orthographe. Idéalement:</p>
<ul>
<li>Un humain devrait être capable de le lire sans difficultés.</li>
<li>Une machine devrait pouvoir le <em>parser</em> facilement pour effectuer la
correction elle-même.</li>
<li>Le correcteur devrait avoir un minimum de mots à …</li></ul><p>Il m’arrive souvent de corriger des documents textes et de devoir noter
facilement les fautes d’orthographe. Idéalement:</p>
<ul>
<li>Un humain devrait être capable de le lire sans difficultés.</li>
<li>Une machine devrait pouvoir le <em>parser</em> facilement pour effectuer la
correction elle-même.</li>
<li>Le correcteur devrait avoir un minimum de mots à recopier.</li>
</ul>
<p>Une solution est de corriger directement le document, puis de faire un
<em>diff</em>. Ça marche, mais ce n’est pas des plus pratiques (on n’a pas
forcément <em>diff</em> partout par exemple, ou encore le texte source n’est
pas disponible pour du Markdown ou du LaTeX) et c’est quand même pas le
plus lisible pour le destinataire. Pour résoudre ce problème, on peut
utiliser <a href="http://etherpad.org"><em>etherpad</em></a> (dont une instance est disponible
chez <a href="http://framapad.org/">FramaSoft</a> pour ceux qui ne veulent pas
auto-héberger) par exemple, qui va garder les corrections en couleur et
ce sera donc très lisible.</p>
<p>Ceci dit, j’utilise une autre solution, qui ne nécessite qu’un éditeur
de texte brut, et qui, un peu comme Markdown, est facilement lisible par
un humain ou une machine. Je ne suis sûrement pas le seul à l’utiliser,
et ça n’a sûrement pas grand chose d’extraordinaire, mais si jamais ça
peut servir à d’autres personnes… (au moins à ceux à qui j’envoie mes
corrections dans ce format ^^)</p>
<p>Le plus simple est de partir d’un exemple. Considérons le texte suivant:</p>
<blockquote>
<p>Cec est un text de démonstratin. Comme vous pouvez aisément le
constater il y a quelques lettres manquntes et quelqueslettres en
troap ou des mauvaises lettres. C’est donc un bon exiample.</p>
</blockquote>
<p>Évidemment, le texte corrigé est:</p>
<blockquote>
<p>Ceci est un texte de démonstration. Comme vous pouvez le constater
aisément il y a quelques lettres manquantes et quelques lettres en
trop ou des mauvaises lettres. C’est donc un bon exemple.</p>
</blockquote>
<p>Pour ce texte, ma proposition de correction serait:</p>
<div class="highlight"><pre><span></span><code>Cec(+i)
text(+e)
démonstrati(+o)n
manqu(+a)ntes
quelques(+ )lettres
tro(-a)p
ex(-ia+e)mple
</code></pre></div>
<p>Avec cette méthode, la correction est très courte, facilement lisible et
très vite écrite. Détaillons-la un peu plus.</p>
<p>Premier constat: il est très rare d’avoir des parenthèses au sein d’un
mot. Et quand il y a des parenthèses, il n’y a jamais (en français
correctement typographié, sauf erreur de ma part) un + ou un - qui suit
une parenthèse ouvrante. On va donc englober dans des parenthèses nos
corrections, directement au sein du mot. Au sein d’une parenthèse, on
commencera toujours par le symbole - suivi de la lettre (ou des lettres
consécutives) à retirer, s’il y a lieu. Puis viendra le symbole + suivi
des lettres à insérer à la place dans le mot.</p>
<p>Quand il manque une lettre dans le mot, elle est dans le champ de vision
au sein de la parenthèse quand on lit le mot, et la lecture du mot est
facilitée, tout en voyant immédiatement qu’il y a une faute à cet
endroit. Quand il y a une lettre en trop, il suffit de ne pas lire la
parenthèse pour avoir le mot complet bien écrit. Quand il y a eu une
substitution, les lettres à insérer sont après le +, et les lettres à
retirer sont après le -. La lecture d’un tel <em>diff</em> est donc très facile.</p>
<p>Pour un ordinateur, il est également très facile de lire un tel diff. Le
code serait le suivant:</p>
<ul>
<li>Découper le texte en mots.</li>
<li>Pour chaque mot, regarder s’il y a un (ou plusieurs) groupe(s) de
parenthèses contenant des + et des -, au format précédent.</li>
<li>Pour chaque mot qui en contient, retirer les caractères suivant le -
et ajouter ceux suivant le +.</li>
</ul>
<p>Une implémentation basique (et mal codée) en Python qui traite un mot
serait :</p>
<div class="highlight"><pre><span></span><code> <span class="k">def</span> <span class="nf">inline_diff</span><span class="p">(</span><span class="n">word</span><span class="p">):</span>
<span class="n">index</span> <span class="o">=</span> <span class="n">word</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">'(-'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">index</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="n">index</span> <span class="o">=</span> <span class="n">word</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">'(+'</span><span class="p">)</span>
<span class="k">if</span> <span class="n">index</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="k">return</span> <span class="n">word</span>
<span class="n">index_end</span> <span class="o">=</span> <span class="n">word</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="s1">')'</span><span class="p">,</span> <span class="n">index</span><span class="p">)</span>
<span class="k">if</span> <span class="n">index_end</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="n">output</span> <span class="o">=</span> <span class="n">word</span><span class="p">[:</span><span class="n">index</span><span class="p">]</span>
<span class="n">action</span> <span class="o">=</span> <span class="s1">'add'</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="n">index_end</span><span class="p">):</span>
<span class="k">if</span> <span class="n">word</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'('</span><span class="p">:</span>
<span class="k">continue</span>
<span class="k">elif</span> <span class="n">word</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'-'</span><span class="p">:</span>
<span class="n">action</span> <span class="o">=</span> <span class="s1">'remove'</span>
<span class="k">elif</span> <span class="n">word</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="s1">'+'</span><span class="p">:</span>
<span class="n">action</span> <span class="o">=</span> <span class="s1">'add'</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">if</span> <span class="n">action</span> <span class="o">==</span> <span class="s1">'remove'</span><span class="p">:</span>
<span class="k">continue</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">output</span> <span class="o">+=</span> <span class="n">word</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
<span class="n">output</span> <span class="o">+=</span> <span class="n">word</span><span class="p">[</span><span class="n">index_end</span><span class="o">+</span><span class="mi">1</span><span class="p">:]</span>
<span class="k">return</span> <span class="n">inline_diff</span><span class="p">(</span><span class="n">output</span><span class="p">)</span>
</code></pre></div>
<p>Il reste à traiter le cas d’un diff complet. Plutôt que de fournir le
texte complet, on peut se contenter de fournir une liste des
corrections, comme la liste précédente, par ordre d’apparition dans le
texte. Avec très peu de précautions nécessaires, une telle liste
pourrait être traitée directement par un ordinateur pour apporter les corrections.</p>
<p><strong>Mise à jour :</strong> Enfin, n’oublions pas d’aborder quelques limitations
de ce système:</p>
<ul>
<li>Si le texte possède deux orthographes d’un mot, il faut prendre des
précautions pour la correction. En particulier, il faut rappeler le
mot à corriger autant de fois qu’il y a de corrections à faire, et
on ne peut pas faire d’option <em>greedy</em>. Cependant, ceci devrait déjà
être le cas si vous utilisez la méthode décrite précédemment.</li>
<li>
<p>Dans le cas du texte suivant:</p>
<blockquote>
<p>Il existe des fois où la technique peut être utilisée moyennant
quelques précautions. Dans cet exemple, les technique précédentes
ne fonctionneront pas sans précautions.</p>
</blockquote>
<p>Si on utilise <code>technique(+s)</code>, c’est la première qui
sera remplacée. Il faut donc étendre cette méthode pour traiter un
contexte suffisant pour effectuer le remplacement sans ambiguïtés.
Le <em>diff</em> adéquat serait:</p>
<p><code>les technique(+s)</code></p>
</li>
<li>
<p>On ne peut pas déplacer de mots facilement avec cette méthode. Plus
exactement, c’est possible mais n’est pas optimal. Considérons le
texte suivant:</p>
<blockquote>
<p>Dans ce texte, les sont mots inversés.</p>
</blockquote>
<p>Moyennant une implémentation un peu plus large de l’algorithme, on
pourrait utiliser la méthode précédente comme ceci, pour corriger
cette phrase:</p>
<p><code>les (-sont) mots (+sont)</code></p>
<p>car rien n’interdit à un mot d’être entièrement supprimé ou ajouté.</p>
</li>
</ul>Documenter son code PHP avec doxygen2014-07-16T15:20:00+02:002014-07-16T15:20:00+02:00Phykstag:localhost,2014-07-16:/Blog/output/2014/07/documenter-son-code-php-avec-doxygen.html<p>Je cherchais hier un moyen de générer une belle doc <span class="caps">PHP</span>, à partir de mes
fichiers sources. Je connaissais quelques outils de la sorte (OcamlDoc,
Sphinx pour Python, JavaDoc etc.) mais je n’avais jamais regardé ça en détails.</p>
<p>Du coup, je suis tombé sur
<a href="http://www.stack.nl/~dimitri/doxygen/">Doxygen</a>, qui supporte une très …</p><p>Je cherchais hier un moyen de générer une belle doc <span class="caps">PHP</span>, à partir de mes
fichiers sources. Je connaissais quelques outils de la sorte (OcamlDoc,
Sphinx pour Python, JavaDoc etc.) mais je n’avais jamais regardé ça en détails.</p>
<p>Du coup, je suis tombé sur
<a href="http://www.stack.nl/~dimitri/doxygen/">Doxygen</a>, qui supporte une très
grande variété de langages, est utilisé par beaucoup de scripts (dont
des très gros comme Drupal) et était largement suffisant pour mes
besoins. Il mange vos sources et génère de <a href="http://maniacbug.github.com/RF24/classRF24.html"><del>belles documentations</del>
des pages de doc lisibles</a>,
en <span class="caps">HTML</span>, LaTeX, <span class="caps">CHM</span> et autres.</p>
<p>J’ai pas trouvé de guides ultra rapides pour démarrer (ok, j’ai pas
vraiment cherché non plus) donc je liste ici les 3 commandes de base,
pour avoir une doc en 5 minutes chrono.</p>
<p>Pour commencer, il faut faire <code>doxygen -g .doxygen</code> dans le
répertoire du projet pour générer un fichier de configuration (option
<code>-g</code>) nommé <code>.doxygen</code>. Voici quelques
paramètres utiles à modifier:</p>
<ul>
<li><code>PROJECT_NAME</code>, mettre le nom de votre projet.</li>
<li>Je voulais générer uniquement une doc <span class="caps">HTML</span>, et tout mettre dans un
dossier doc. J’ai donc mis <code>OUTPUT_DIRECTORY</code> à
<code>"doc/"</code>, puis <code>HTML_OUTPUT</code> à
<code>.</code> (pour que la doc <span class="caps">HTML</span> aille dans <code>doc/</code>)
et enfin <code>GENERATE_LATEX</code> à <code>NO</code> pour ne
pas générer de doc en LaTeX.</li>
<li>Enfin, je voulais traiter tous les fichiers de mon projet, donc j’ai
mis l’option <code>RECURSIVE</code> à <code>YES</code>.</li>
</ul>
<p>Une fois tout ceci fait, il faut que vos commentaires soient au bon
format pour que doxygen les lise. Un exemple est disponible
<a href="https://raw.githubusercontent.com/Phyks/Freeder/master/inc/functions.php">ici</a>.</p>
<p>En gros, il faut à chaque fois redoubler les commentaires
<code>/** … */</code> pour que doxygen les <em>parse</em>. Les premières
lignes de texte dans chaque cas sont un petit paragraphe descriptif. Il
est possible d’ajouter un plus long paragraphe après avoir sauté une
ligne. Doxygen utilise ensuite des tags <code>@quelquechose</code> pour
noter les paramètres, les valeurs de retours, les copyrights etc.</p>
<p><strong>Important</strong>, ne pas oublier de dire à doxygen d’utiliser le fichier
courant avec un <code>@file</code> dans le commentaire global du fichier.</p>
<p>Une fois tous vos fichiers <em>taggés</em> correctement, lancer <code>doxygen
.doxygen</code> depuis la racine de votre projet pour générer la
doc. Vous obtiendrez une belle documentation <a href="https://freederteam.github.io/Freeder/doc/files.html">comme
ça</a> (ok, il y a
encore du boulot sur celle-ci…).</p>Specific Vim config per Git repository2014-07-15T22:20:00+02:002014-07-15T22:20:00+02:00Phykstag:localhost,2014-07-15:/Blog/output/2014/07/specific-vim-config-per-git-repository.html<p>I was looking for a way to add custom vim options on a per-repo basis.
The standard way I saw for now, was adding some comments to change the
Vim config on a per-file basis. There were some alternatives which were
working for any project folder (and not only git …</p><p>I was looking for a way to add custom vim options on a per-repo basis.
The standard way I saw for now, was adding some comments to change the
Vim config on a per-file basis. There were some alternatives which were
working for any project folder (and not only git repos) but they were
only working if you start Vim from the root of the project, or they were
exploring the tree from local folder up to root (and needed a plugin).
None of them were satisfactory.</p>
<p>When I edit a file and need specific Vim configuration, it is usually
inside a git repo. So, it is easy to know what is the root folder, and I
just wanted to search for a <code>Vimrc</code> file in this folder. No
complicated tree searching, working from anywhere inside the repo, no
per-file specific configuration.</p>
<p>First of all, the magic command I used to find the git root folder is
<code>git rev-parse --show-top-level</code>.</p>
<p>Then, all I had to do is wrap it correctly in my <code>.vimrc</code>:</p>
<div class="highlight"><pre><span></span><code><span class="c">" Git specific configuration</span>
<span class="k">let</span> git_path <span class="p">=</span> system<span class="p">(</span><span class="s2">"git rev-parse --show-toplevel 2>/dev/null"</span><span class="p">)</span>
<span class="k">let</span> git_vimrc <span class="p">=</span> substitute<span class="p">(</span>git_path<span class="p">,</span> <span class="s1">'\n'</span><span class="p">,</span> <span class="s1">''</span><span class="p">,</span> <span class="s1">''</span><span class="p">)</span> . <span class="s2">"/.vimrc"</span>
<span class="k">if</span> <span class="p">!</span>empty<span class="p">(</span>glob<span class="p">(</span>git_vimrc<span class="p">))</span>
<span class="k">sandbox</span> exec <span class="s2">":source "</span> . git_vimrc
<span class="k">endif</span>
</code></pre></div>
<p>Note: I use sandbox to prevent arbitrary functions from being executed.</p>
<p>This small code, added at the end of your <code>.vimrc</code> will just
look for a <code>.vimrc</code> at the root the git repository and
source it if possible. That’s exactly what I wanted :)</p>Quick and dirty benchmark of RSS/ATOM parsing libs2014-07-10T17:25:00+02:002014-07-10T17:25:00+02:00Phykstag:localhost,2014-07-10:/Blog/output/2014/07/quick-and-dirty-benchmark-of-rssatom-parsing-libs.html<p><strong><span class="caps">EDIT</span>:</strong> I just realized that the <span class="caps">PHP</span> function <code>microtime</code>
does not return what I expected. This does not change much the results
(to compare the solutions) but change the units. I update the results accordingly.</p>
<p>As I wrote in a <a href="http://localhost/Blog/output/2014/07/mon-lecteur-rss-ideal.html">previous
article</a>. I am working
on a rss reader that …</p><p><strong><span class="caps">EDIT</span>:</strong> I just realized that the <span class="caps">PHP</span> function <code>microtime</code>
does not return what I expected. This does not change much the results
(to compare the solutions) but change the units. I update the results accordingly.</p>
<p>As I wrote in a <a href="http://localhost/Blog/output/2014/07/mon-lecteur-rss-ideal.html">previous
article</a>. I am working
on a rss reader that could fit my needs. For this purpose, I am
currently trying to see which way is the best way to parse <span class="caps">RSS</span> and <span class="caps">ATOM</span>
feeds in <span class="caps">PHP</span>.</p>
<p>I searched on the web for benchmarks, but I could only find old
benchmarks, for old version of the libs and weird stuff (like parsing
directly the feed with regex). So, I did a quick and dirty benchmark
(and this is the reason why this article is in english :).</p>
<h2>Which lib is the best one to parse <span class="caps">RSS</span> and <span class="caps">ATOM</span> feeds ?</h2>
<p>I searched on the web for the available solutions. I found three main
solutions (ordered from the most lightweight one to the less lightweight one):</p>
<ul>
<li><a href="https://github.com/broncowdd/feed2array">feed2array</a>, a lib by
<a href="http://warriordudimanche.net/">Bronco</a> which is basically a wrapper
around SimpleXML and is used by
<a href="http://lehollandaisvolant.net/">timo</a> in his <span class="caps">RSS</span> reader implemented
in <a href="https://github.com/timovn/blogotext">blogotext</a>. So it is tested
on a quite wide range of feeds and should be considered fully working.</li>
<li><a href="http://lastrss.oslab.net/">lastRSS</a>, a dedicated lib written in <span class="caps">PHP</span></li>
<li><a href="http://simplepie.org">SimplePie</a>, the well known lib, very
complete, able to handle a wide range of feeds, correctly <strong>and</strong>
incorrectly formatted, but very heavy.</li>
</ul>
<p>My goal was just to do a quick benchmark, so it is complete dirty and
may not be very precise, but I did not need more. I did not test
extensively all the available libs, especially all the wrappers around
SimpleXML as the one I found was sufficient, and is basic enough to
reflect a general result.</p>
<p>My test lies on six <span class="caps">RSS</span> and <span class="caps">ATOM</span> feeds (both of them, to be sure that
the lib worked on them) with a total of 75 articles. I parse them with
the corresponding lib, and I do not display anything but the total time
to parse them. I do not mind the ability of the lib to handle specially
malformed feeds as these should not exist and parsing them may encourage
their use. So, I am just interested in the time needed to parse these 6 feeds.</p>
<p>The three libs parsed all of them successfully. I ran the test on my
laptop, which can be considered almost 100% idle.</p>
<p>The results are:</p>
<table>
<thead>
<tr>
<th>Library</th>
<th>Time</th>
</tr>
</thead>
<tbody>
<tr>
<td>feed2array (and similar basic simpleXML based solution)</td>
<td>about 40ms</td>
</tr>
<tr>
<td>lastRss</td>
<td>about 120ms and I got some mistakes</td>
</tr>
<tr>
<td>SimplePie</td>
<td>about 280ms</td>
</tr>
</tbody>
</table>
<p>So, for my personnal case, I would simply say “the simpler the better”
and go for feed2array that works perfectly on the feeds I want to use
and is way faster than the overkill libraries. Very often I read that
SimplePie was heavy and slow (despite their advertisement as “super
fast”) and it seems to be confirmed by my results.</p>
<p>In conclusion, however these results are just to be considered as orders
of magnitude, and not precise measurements, I would say that you should
avoid any complicated and overkill library unless you really need some
of the advanced features it has. Your script will be way faster (up to 5
times faster or so according to these results).</p>
<p><em>Note:</em> I only focused on these three libraries as it appears that they
are the three main libraries available for this purpose (except for
feed2array for which there are plenty of similar scripts). I wanted only
scripts under a fully open source license, which eliminated some of the
others. The only notable ones that I could have taken into account (I
think) are the feed library from Zend, but I did not want to search for
a way to get only the relevant functions from Zend, and the newly
integrated <span class="caps">PHP</span> extensions such as <span class="caps">XSLT</span>. However, these <span class="caps">PHP</span> extensions
are not widely available, and not built-in at all, so they may not be
available on most of the shared hostings.</p>
<h2>Store in a database / files or parse it each time ?</h2>
<p>Next question I had was how do this time compare with retrieving infos
from a database. For this purpose, I compared three times:</p>
<ul>
<li>time to parse the feeds using feed2array, which is about 40ms, as
found before.</li>
<li>time to load the arrays representing the feeds from serialized and
gzipped files, which is about 8ms.</li>
<li>time to load 75 elements (id, description, guid, link and pubDate)
from a sqlite database, not optimized at all, which is about 2ms.</li>
</ul>
<p>As we could expect, it is longer to parse the feeds than to load them
from a storage. So, it is definitely not a good idea to parse them at
each page generation. Plus <span class="caps">RSS</span> format is not practical at all to do
search and complex queries.</p>
<p>The legit solutions are then to use flat files or a database. The
difference between the two times is not so large, considering that files
are gzipped and that I actually stored a bit more information in the
file than in the table.</p>
<p>However, there is not much optimization to do with files, whereas there
are many ways to improve my results with a database. For instance, I
used a basic sqlite table, without any potential optimization. But I
could have used a more robust solution. If performances are really a
concern, I could even use a temporary database, stored in <span class="caps">RAM</span>, to store
the feeds elements. If this table is lost, that is not a big deal, as I
will only have to do a refresh to get them back.</p>
<p>Finally, one of the major problems with SQLite seems to be that it may
be slow to write and completely locks the database when writing inside.
But, this is also the case for flat files.</p>
<p>In conclusion, I would say that the best solution appears to be SQLite
with <span class="caps">PDO</span>. Actually, the use of <span class="caps">PDO</span> will enable to change the database
very easily, and SQLite might be as good (if not better) as flat files.</p>
<p><em>Note:</em> I put all my code and the test rss feeds in a zip archive
available <a href="https://pub.phyks.me/benchmark_rss.zip">here</a>.</p>Mon lecteur RSS idéal2014-07-10T17:24:00+02:002014-07-10T17:24:00+02:00Phykstag:localhost,2014-07-10:/Blog/output/2014/07/mon-lecteur-rss-ideal.html<p><strong><span class="caps">EDIT</span> :</strong> J’ai repris quelque peu le commentaire de FreshRSS, après
discussion avec son auteur. J’avais raté certaines options en particulier.</p>
<p><strong><span class="caps">EDIT</span> 2:</strong> Suite à quelques retours sur cet article, je tiens à
préciser que la première partie de l’article (« Panorama de ce qui
existe ») est volontairement courte …</p><p><strong><span class="caps">EDIT</span> :</strong> J’ai repris quelque peu le commentaire de FreshRSS, après
discussion avec son auteur. J’avais raté certaines options en particulier.</p>
<p><strong><span class="caps">EDIT</span> 2:</strong> Suite à quelques retours sur cet article, je tiens à
préciser que la première partie de l’article (« Panorama de ce qui
existe ») est volontairement courte et caricaturale. C’est une
compilation caricaturale de réflexions que j’ai entendues, et je ne
m’étends volontairement pas dessus, pour ne pas allourdir inutilement
cet article qui vise d’abord à présenter les points qui me semblent
importants pour mon lecteur de flux <span class="caps">RSS</span> idéal.</p>
<p><em>Attention, cet article est un bon pavé et il est sûrement plein de
répétitions… :)</em></p>
<p>Sam&Max ont écrit récemment sur <a href="http://sametmax.com/pourquoi-sametmax-com-utilise-wordpress/">leur moteur
idéal</a>. Le
moteur de blog est un réel problème, et j’adhérerais immédiatement à un
moteur de blog qui satisfasse leurs critères (mais bon, pour l’instant
ma solution maison patchée de partout fonctionne pas trop mal :). En
revanche, un autre point mérite une bonne réflexion et pourrait être
grandement amélioré et modernisé : le lecteur <span class="caps">RSS</span>.</p>
<p>J’utilise actuellement <a href="https://github.com/ldleman/Leed">Leed</a> sur mon
serveur. J’en suis globalement satisfait, mais certains points m’agacent
et ne sont pas résolus, au fil des versions. Pourtant, après avoir fait
le tour des solutions existantes, c’est la solution la plus
fonctionnelle que j’ai trouvée… Je profite donc de ce billet pour
dresser un bilan de ce que j’ai vu passer sur les lecteurs <span class="caps">RSS</span> et ce que
je voudrais trouver dans mon lecteur <span class="caps">RSS</span> idéal.</p>
<h2>Panorama de ce qui existe</h2>
<p>Tout d’abord, sebsauvage a fait il y a quelques temps un <a href="http://sebsauvage.net/rhaa/index.php?2013/03/15/17/15/39-arretez-de-pleurer-google-reader-hebergez-un-lecteur-rss-chez-vous">petit tour
d’horizon des solutions de lecteurs <span class="caps">RSS</span> à
héberger</a>.
Je vais faire court, au risque de m’attirer les critiques :</p>
<dl>
<dt>Leed</dt>
<dd>On attend le support du multi-utilisateur depuis un moment, il
utilise <code>mysql_</code> qui est déprécié, base MySQL
obligatoire, quand même assez lourd, une licence non libre (<span class="caps">CC</span> <span class="caps">BY</span> <span class="caps">SA</span>
<span class="caps">NC</span>), des développeurs principaux indisponibles (le
<a href="http://leed.idleman.fr/">wiki</a> est globalement <span class="caps">HS</span> pour l’instant),
un thème de base très moche, pas si simple à installer pour Mme
Michu, des thèmes qui sont quand même limités, et <a href="https://github.com/ldleman/Leed/issues/391">bloqués par le
dépôt principal</a>…</dd>
<dt>KrISS Feed</dt>
<dd>C’est moche, pas fonctionnel. Je ne me suis pas attardé sur le
reste, qui semble assez standard.</dd>
<dt>FreshRSS</dt>
<dd>Il peut gérer beaucoup d’articles (100k annoncés sur le
<a href="http://freshrss.org/">site</a>). C’est pas très bô (beau / ergonomique
/ efficace) non plus, trop compact (notamment sur smartphone, quand
on a des gros doigts :), et les infos importantes ne sont pas mises
en valeur (à mon avis, les flux sont les éléments principaux, à
mettre en valeur ; sur <span class="caps">FRSS</span>, mon œil est beaucoup plus attiré par
les dossiers et les boutons). C’est aussi compliqué à installer
(base MySQL, même si c’est pas si compliqué, Cron manuel,
instructions dans le <span class="caps">README</span> que ne lit pas Mme Michu), et cela
risque de bloquer Mme Michu… Ses avantages par contre : il supporte
très bien la charge, et l’intégration de Mozilla Persona est
originale. Il a aussi de nombreuses possibilités, pour peu qu’on
fouille un peu les menus de configuration.</dd>
<dt>Aeres</dt>
<dd>Site <span class="caps">HS</span>, mais ça a l’air très moche aussi.</dd>
<dt>Miniflux</dt>
<dd>Seul concurrent sérieux, à la vue du site. De très bonnes idées,
comme le <em>full content</em> et la suppression des trackers à la volée,
mais quand on ouvre la page de démo, c’est moche… et
<strong>inutilisable</strong> ce qui est vraiment dommage pour un script qui est
hébergé contre paiement. C’est minimaliste, trop minimaliste. Les
liens pour marquer comme lus, non lus, supprimer etc sont
invisibles, le texte de l’article non sélectionné est illisible,
surtout sur un mobile en plein soleil, il n’y a aucun support de
plugins, les raccourcis claviers sont complètement dissociés du
contrôle à la souris et il me semble assez lourd quand on charge de
nombreux articles.</dd>
<dt>selfoss</dt>
<dd>Ça commence bien, le site est beau et les <em>screenshots</em> donnent
envie, mais qu’en est-il vraiment ? Déjà, c’est <strong>compliqué</strong> :
l’installation est compliquée, la configuration se fait dans un
fichier <code>config.ini</code>, il n’y a pas de démo disponible,
et quand on finit par l’installer pour le voir en action, on se rend
compte que ce n’est quand même pas très utilisable.</dd>
<dt><span class="caps">RSS</span> Lounge</dt>
<dd>Connu pour sa lourdeur, il fait tout (ou presque, il ne fait pas
encore le café), on passe.</dd>
<dt>cartulary</dt>
<dd>C’est compliqué, le <span class="caps">README</span> est paumatoire, alors qu’il n’y a
vraiment aucune raison d’expliquer de façon si compliquée une
installation somme toute assez basique.</dd>
<dt><span class="caps">RSS</span> Miner</dt>
<dd><a href="http://www.rssminer.net/">Le site</a> ne s’affiche pas correctement
chez moi, la barre de gauche cachant la moitié de la page et ne se
fermant pas, je m’attends au pire et je n’ai pas regardé plus en détails.</dd>
<dt>News Blur</dt>
<dd>Il y a des idées, notamment le côté social. Mais c’est compliqué, et
hors de portée de beaucoup de monde, car ça tourne sous Django, avec
du MongoDB et du PostgreSQL. Je ne suis pas sûr que le côté social
soit compatible entre plusieurs instances et utilise un réseau
décentralisé pré-existant, qui permettrait de le plugger facilement
avec Diaspora ou n’importe quel autre logiciel du genre, et évitant
de multiplier les réseaux et les protocoles.</dd>
<dt>Feed <span class="caps">HQ</span></dt>
<dd>Inscription obligatoire pour tester, c’est aussi du python + redis +
postgresql + elasticsearch, donc on oublie pour Mme Michu.</dd>
</dl>
<h3>Que conclure de ce panorama ?</h3>
<p>Quoi que je fasse, je reviens vers Leed. De nombreuses fonctionnalités
sont annoncées depuis un moment, et j’attends qu’elles voient le jour,
mais il reste le plus fonctionnel et celui qui colle le mieux avec mon
lecteur <span class="caps">RSS</span> idéal, tout en restant loin de la perfection. Le reste est
moche, complexe, lent, et même les solutions payantes (mais opensources)
ne s’en sortent guère mieux. Je n’utilisais pas Google Reader, mais s’il
était dans la tradition des outils Google (simple, fonctionnel et
rapide), je n’ai pas (encore ?) trouvé de réelle alternative.</p>
<p>Concernant Leed, la première étape est bien sûr de changer le thème par
défaut (Marigolds) pour un meilleur thème. Le plus complet et maintenu
actuellement est <a href="https://github.com/tmos/greeder">Greeder</a> de
<a href="http://tomcanac.com/">tmos</a> (bien que <a href="http://rss.remitaines.fr/">Hot
Beer</a> se défende, même si je n’adhère
absolument pas au format <em>webzine</em>). tmos travaille sur un pack Leed +
greeder et sur l’intégration de Leed dans
<a href="https://yunohost.org/">Yunohost</a>, qui devrait lui redonner un peu de fraîcheur.</p>
<h2>Mais du coup, c’est quoi mon lecteur <span class="caps">RSS</span> idéal ?</h2>
<h3>Rapidité, simplicité, fonctionnalité</h3>
<p>Je met à jour mon lecteur <span class="caps">RSS</span> toutes les heures, et j’y passe donc
quasiment une fois par heure. Je ne veux pas passer dix minutes à chaque
fois pour réussir à cliquer sur le bon bouton, ou pour attendre que la
page soit chargée.</p>
<p>Il faut donc qu’il soit beau, intuitif (pour ça, Leed + greeder remplit
bien ce rôle), rapide et fonctionnel. Le but est aussi de lire des
articles, pas de voir défiler des titres, donc il faut que les articles
soient affichés en entier (mais personnalisables <em>via</em> une option pour
satisfaire tout le monde), sans avoir besoin de cliquer trois fois sur
chaque article pour le lire.</p>
<p>Je le regarde de partout, et beaucoup sur mon portable, dans les
transports. Or, bien souvent, il n’y a pas de réseau dans les
transports, et je ne veux pas d’une <a href="http://standblog.org/blog/post/2014/06/29/Web-Entrepreneur-Conference-videos-disponibles">énième app quand du <span class="caps">HTML5</span> peut le
faire</a>.
Du coup, un thème responsive, des actions tactiles (comme Greeder, en
plus étendu) et une utilisation du <em>local storage</em> et le tour est joué :)</p>
<p>Toutes ces fonctionnalités (et celles qui vont suivre) peuvent paraître
en contradiction avec « être léger, rapide et fonctionnel », mais si le
script est suffisamment compartimenté, on peut ne charger que ce qui
sera utile à l’affichage et conserver un grand nombre de fonctionnalités
avancées, sans alourdir nécessairement le script (sauf dans le cas où
tout serait activé en même temps).</p>
<h3>Extensibilité et customisation</h3>
<p>On ne peut pas faire un logiciel parfait, qui satisfasse tout le monde.
Plutôt que d’opter pour le minimalisme et se priver ainsi de fonctions
avancées, un système de plugins bien pensé me paraît mieux. Celui de
Leed est bien pour ça, même s’il manque un peu de documentation.
Idéalement, il faudrait même que les plugins et thèmes existants pour un
des lecteurs <span class="caps">RSS</span> les plus répandu actuellement soient compatibles (mais
là, je rêve je pense :).</p>
<p>Quelques idées de plugins cools en vrac :</p>
<ul>
<li>Recherche : très souvent je lis des articles, puis quelques jours
plus tard je réalise que j’aurais du les garder de côté car j’en ai
besoin. Sauf qu’à ce moment, je ne sais plus sur quel flux je l’ai
lu, et c’est une galère de le retrouver. Un plugin de recherche sur
l’agrégateur permet de résoudre ce problème.</li>
<li>Une implémentation de
<a href="https://github.com/sebsauvage/rss-bridge">rss-bridge</a> pour le côté user-friendly.</li>
<li>Des plugins spécifiques par flux, pour afficher les conversations
entre shaarli en tant que conversations par exemple.</li>
<li>Annotation de texte en direct pour noter rapidement des idées, des
corrections de typo etc.</li>
</ul>
<p>Pour le côté user friendly et l’adoption par Mme Michu, il faudrait
aussi une liste de plugins « officiels » (c’est-à-dire respectant les
guidelines et donc compatibles) simple, à la wordpress. Il suffirait
alors d’envoyer l’archive dans l’interface admin pour l’installer automatiquement.</p>
<p>Idéalement, il faudrait des coding guidelines strictes, qui manquent sur
les projets actuels. Notamment sur la façon d’écrire un thème ou sur les
balises à utiliser dans un thème, afin de garantir la cohérence de
l’interface et la rapidité du script. Leed par exemple, a un dépôt
<a href="https://github.com/ldleman/Leed-market">market</a> très hétérogène, et des
thèmes qui n’ont pas de base commune rendant très difficile
l’implémentation de nouveau code sur plusieurs thèmes. Pire, certains
plugins doivent être adaptés pour chaque thème, ce qui est une perte de
temps considérable.</p>
<h3>Une gestion fine des flux</h3>
<p>Une autre fonctionnalité qui me paraît importante est de pouvoir gérer
finement les flux, c’est-à-dire pouvoir prioriser, classer, trier et
filtrer des flux très facilement.</p>
<p>Un premier point est la gestion des doublons. Très souvent, il arrive
d’avoir des articles similaires, sur le même sujet, voire même des
articles tout simplement identiques, si certains flux se recoupent. Le
premier cas est difficile à trier et à filtrer (même si idéalement ces
articles devraient pouvoir être regroupés ensemble), mais le deuxième
est très simple à filtrer. Les doublons devraient donc être masqués et
gérés comme un seul et même article.</p>
<p>Un autre point important est la présence du multi-utilisateur. Cela
permet ainsi de ne charger qu’une seule fois les liens communs à
plusieurs comptes, et d’accélerer le rafraîchissement des liens ainsi
que d’alléger la charge des serveurs. Je vois deux cas d’utilisation
importants : pouvoir avoir une seule instance pour tout une famille, et
pouvoir avoir différents comptes par activité (un compte pro et un
compte perso par exemple).</p>
<p>D’autres fonctionnalités sympathiques sont proposées par certains
lecteurs <span class="caps">RSS</span>, notamment la gestion de la priorité des flux, pour
prioriser certains flux.</p>
<p>Je pense aussi qu’il y a moyen de faire des trucs très sympas avec les
dossiers, qui sont bien trop rigides comme fonctionnement (et que je
n’utilise pas personnellement). Sûrement un système de tags, ou un
système flexible par mot-clé. Mais je n’ai pas encore d’idées précises à
apporter pour cette réflexion. N’hésitez pas à partager les votres :)</p>
<h3>Transparence et protection de la vie privée</h3>
<p>Un des principaux avantages de s’auto-héberger est d’avoir les
contraintes de transparence, de sécurité et de protection de la vie
privée qu’on se fixe, au lieu d’être dépendant d’une solution tierce sur
ces points.</p>
<p>Un lecteur <span class="caps">RSS</span> idéal, et toujours dans l’optique de l’utilisation par le
plus grand nombre, devrait :</p>
<dl>
<dt>afficher de manière claire les logs disponibles</dt>
<dd>on ne devrait jamais devoir aller chercher une information dans un
obscur fichier de log écrit dans le répertoire du script, ou pire,
dans les logs Apache. Au contraire, ces informations (historique de
connexions, historiques de mise à jour, …) devraient être
disponibles dans l’interface directement, de façon claire et
compréhensible en un clin d’œil.</dd>
<dt>des statistiques claires</dt>
<dd>de même, une fonctionnalité absente de nombreux lecteurs <span class="caps">RSS</span> et qui
me semble pourtant plutôt basique est la possibilité de voir en un
clin d’œil quels sont les flux fréquemment mis à jour, quels sont
les flux les plus actifs, les moins actifs, etc., ceci afin de
pouvoir très facilement trier ses flux et supprimer les flux morts.
Il m’est arrivé plusieurs fois d’avoir un flux qui a changé
d’adresse, ou qui était momentanément indisponible, et de mettre
plusieurs jours à m’en rendre compte, faute d’affichage clair comme
“attention, le flux <span class="caps">XXX</span> n’a pas été mis à jour depuis N jours, alors
qu’il avait une fréquence habituelle de M articles / jour”</dd>
<dt>régler finement les permissions</dt>
<dd>S’auto-héberger, c’est aussi pouvoir régler finement les fonctions
avancées de ses logiciels. J’utilise intensivement la vue anonyme de
Leed, pour ne pas avoir à me connecter à chaque visite, et car je
trouve ça pratique de pouvoir voir les flux <span class="caps">RSS</span> que les autres
suivent, on découvre bien souvent de nouveaux flux top comme ça.
Mais sur la plupart des lecteurs actuels, soit tout est public, soit
tout est privé. Or je ne veux pas forcément que <strong>tous</strong> mes flux
soit publics. En particulier, certains flux liés à des services que
j’utilise (mon Owncloud, par exemple) ne devraient pas être publics.</dd>
<dt>être compatible avec les autres outils libres à disposition</dt>
<dd>Enfin, même si je souhaite beaucoup de fonctions dans mon lecteur
<span class="caps">RSS</span>, je ne veux pas qu’il devient un monstre polycéphal qui fait
tout. Le libre a cela de merveilleux qu’il existe une infinité de
petits outils qui font une seule petite tâche, mais la font très
bien. Pourquoi implémenter aussi une gestion des favoris, quand
Owncloud le propose, quand shaarli marche du tonerre et est de
surcroît très simple à installer, etc. Il faut donc au contraire
prévoir d’être compatible avec ces autres outils, pour que le libre
soit cohérent. En particulier, owncloud propose un flux <span class="caps">RSS</span>
accessible après authentification (<span class="caps">POST</span>) des “activités” sur le
compte. Pratique pour suivre des dossiers partagés. Mais très peu de
(si ce n’est aucun) lecteur <span class="caps">RSS</span> disponible ne gère cette
authentification =(.</dd>
<dt>promouvoir la vie privée de l’utilisateur</dt>
<dd>En utilisant son propre lecteur <span class="caps">RSS</span> auto-hébergé, on a un contrôle
total sur nos flux, et on ne divulgue pas d’informations non
contrôlées à un tiers (typiquement l’hébergeur du lecteur <span class="caps">RSS</span>, qui
pourra alors nous cibler plus finement). J’aimerais pouvoir
retrouver ça dans mon lecteur avec un filtrage des liens feedburner
par défaut, pour supprimer ces redirections et les remplacer par des
liens directs, ainsi qu’un filtrage des publicités dans les flux, un
peu à la manière des
<a href="https://github.com/ldleman/Leed-market">plugins</a> urlclean et
adblock pour Leed. Il pourrait aussi cacher le referer lors de
l’ouverture d’un lien externe, etc. Il y a énormément de
possibilités de ce côté.</dd>
</dl>
<h3>Toujours garder l’ergonomie en tête</h3>
<p>L’ergonomie est sûrement un des points faibles des lecteurs <span class="caps">RSS</span>
disponibles actuellement (et du logiciel libre ?). Elle est bien souvent
négligée, et cela prive bon nombre d’utilisateurs d’utiliser les scripts
en question.</p>
<p>Pourtant, il y a moyen de faire beaucoup de choses, notamment en usant
(abusant ?) de JavaScript et des fonctionnalités récentes (transitions
<span class="caps">CSS</span>, <span class="caps">HTML5</span> etc). Du drag&drop s’implémente facilement, et facilite
grandement l’utilisation pour beaucoup d’utilisateurs. Décrémenter un
compteur d’éléments non lus en JavaScript chaque fois qu’on marque un
élément comme lu prend 3 lignes de JavaScript et pourtant cela n’a été
implémenté que récemment dans
<a href="https://github.com/tmos/greeder/commit/446a521d240db62bc8350f54b31148429afeddb7">Greeder</a>
et dans le thème par défaut de Leed.</p>
<p>De plus, j’ai besoin d’une application web pour ne pas dépendre de
l’ordinateur (ou du téléphone) que j’utilise. Que je sois sur mon
téléphone, mon ordinateur ou n’importe quel autre périphérique, je
retrouve mes news dans le même état, sans synchronisation compliquée, et
sans développer un logiciel différent par périphérique. Le web est
vraiment magique pour ça. Mais ce n’est pas pour autant que je ne veux
pas que cette <em>webapp</em> se rapproche le plus possible d’une application
native (qui sont bien souvent des <em>wrappers</em> autour d’une interface web,
sur mobile, de toutes façons). Ainsi, sur mon portable, je veux
retrouver des actions tactiles, un stockage en <em>local storage</em> car je
risque d’être déconnecté sans raison, et une interface utilisable
pleinement sans jouer avec le zoom. Et sur mon ordinateur, je veux
pouvoir bénéficier d’une navigation au clavier, avec des raccourcis
claviers, et de fonctionnalités avancées telles que le rafraîchissment
régulier ou <a href="https://github.com/tmos/greeder/issues/71">la
notification</a>, afin de se
rapprocher le plus possible d’une application (et peut être un jour
tourner dans sa propre instance du navigateur, pour ressembler vraiment
à une application ?).</p>
<p>Côté interface, celle-ci doit faciliter la lecture en mettant l’accent
sur le contenu et les actions importantes. Il y a aussi beaucoup de
boutons qui ont une fonction peu claire dans les scripts que j’ai pu
voir : double négation dans les questions qui nous fait répondre « oui »
quand on voulait dire « non », pas de rappel du nom du dossier quand on
veut marquer tout un dossier comme lu (ce qui nous fait nous demander si
on a bien cliqué sur le bon bouton)… D’autre part, quand je qualifiais
les interfaces de « moches » au début de cet article, c’était bien
souvent que l’interface était peu claire / paumatoire / clicodrôme.</p>
<p>La mode est au <em>scroll</em> infini. C’est bien pratique quand on a une
connexion permanente, mais dès que la connexion coupe, qu’on recharge la
page, et qu’on se retrouve tout en haut, c’est nettement moins drôle. Du
coup, vive la pagination, en gardant une option pour le <em>scroll</em> infini,
pour ceux qui l’aiment particulièrement. Par contre, si le <em>local
storage</em> est très largement utilisé, le <em>scroll</em> infini peut
s’envisager, car la perte de connexion ne bloquera pas la page.</p>
<p>Enfin, un dernier point essentiel à mon avis est la possibilité de se
connecter automatiquement et d’avoir un <em>bookmarklet</em> efficace pour
ajouter des flux (idéalement, une intégration directe avec le module
d’abonnement de Firefox :). Leed a un bon <em>bookmarklet</em> mais la
connexion automatique n’est arrivée que récemment. Et attention sur ce
point, <a href="https://github.com/sebsauvage/Shaarli">Shaarli</a> a une connexion
automatique erratique, qui a tendance à ne pas passer chez certains hébergeurs.</p>
<h3><del>Paraître</del> Être sérieux</h3>
<p>Trop de scripts de ce genre ont aussi des traductions approximatives,
<em>monkey patchée</em> ou bourrées de fautes. L’inernationalisation est
importante de nos jours et ne doit pas être négligée, surtout qu’elle
est désormais facilitée par les outils disponibles et qu’elle n’est pas
si problématique si pensée depuis le début. Faire un test sur les
nombres à afficher pour afficher l’accord si besoin n’est pas très long,
et il est possible de faire une fonction à appeler pour le faire à
chaque fois. Ce n’est pas grand chose, mais c’est plus propre, plus beau
et plus tentant. Une bonne traduction, une bonne licence, un code en
anglais et des <em>coding guidelines</em> motiveront plus les gens pour écrire
du code et faire des contributions.</p>
<p>Il faut aussi avoir une sortie régulière de versions, quitte à sortir
des versions rapprochées. Si toutes les nouvelles fonctions sont
regroupées dans une branche <code>dev</code> et regroupées dans une
version stable une fois par an, Mme Michu ne verra qu’une version par
an, et se dira donc que le développement est lent, même si chaque
version apporte énormément de nouveautés. Au contraire, un dépôt avec
des commits réguliers est plus attirant car on se dit que le logiciel
vit, qu’il est suivi et qu’on n’aura donc pas à attendre longtemps si on
rencontre un problème avec. Personnellement, si je rencontre un problème
bloquant avec un logiciel et que celui-ci n’est pas résolu rapidement
(en quelques semaines tout au plus), que je le veuile ou non, j’oublie
l’existence de ce logiciel, je trouve des alternatives, et je retombe
dessus par hasard quelques mois plus tard.</p>
<p>De même, on ne peut pas tout développer, et on ne peut pas tout
réinventer. Du coup, il devient important de virer les fonctionnalités
inutiles, ou qui font doublon avec d’autres programmes, pour ne pas
réinventer la roue et se consacrer sur les points essentiels pour le script.</p>
<h3>Et tout cela… pour tous</h3>
<p>Comme j’ai déjà insisté pas mal dessus, je reprendrais juste brièvement
quelques points dans cette partie. Mais pour rester dans l’érgonomique
et le beau, un tel script devrait être facile à installer, à configurer
et à utiliser, par tous.</p>
<p>Ceci passe par une interface user friendly, utilisant pleinement les
fonctionnalités offertes par les navigateurs aujourd’hui (drag&drop,
<span class="caps">AJAX</span>, …). Ceci passe aussi par l’internationalisation, la présence d’une
vraie liste d’extensions, facilement utilisable, une doc claire et à
jour et un fonctionnement identique (dans la mesure du possible) sur la
plupart des hébergements disponibles.</p>
<p>Du côté de la licence, un tel lecteur <span class="caps">RSS</span> devrait être sous une licence
libre (dans le sens de logiciel libre), ce qui n’est malheureusement pas
le cas de Leed aujourd’hui (sous licence <span class="caps">CC</span>-<span class="caps">BY</span>-<span class="caps">NC</span>-<span class="caps">SA</span>), qui a d’ailleurs
une licence ambiguë, déconseilleé pour les codes sources (voir
<a href="http://freear.org.uk/content/creative-commons-licenses-software-just-say-no">ici</a>
ou
<a href="http://wiki.creativecommons.org/Frequently_Asked_Questions#Can_I_use_a_Creative_Commons_license_for_software.3F">ici</a>)
et complexe comme le montre <a href="http://www.framablog.org/index.php/post/2012/10/15/non-commercial-creative-commons">cet article chez
Framasoft</a>,
un comble pour une licence qui se veut simple et intuitive. :)</p>
<p>Enfin, un des principaux points est sûrement de pouvoir mettre à jour
les flux facilement, sans y penser et sans intervention. Actuellement,
la plupart des lecteurs nécessitent une intervention de l’utilisateur
pour ajouter une <em>crontask</em>. C’est compliqué, source de problèmes,
d’erreurs en recopiant etc, et ça complique l’installation pour pas mal
de monde. Il y a sûrement moyen de rendre cela plus facile aussi, en
tout cas ça serait top si c’était le cas.
<a href="http://owncloud.org/">Owncloud</a> par exemple propose de lancer les
tâches par <span class="caps">AJAX</span>, webcron ou cron, sans configuration de la part de l’utilisateur.</p>
<h2>Conclusion</h2>
<p>Aucun lecteur <span class="caps">RSS</span> ne me satisfait pleinement, mais Leed me paraît le
moins imparfait à l’heure actuelle. En prenant des briques à gauche, à
droite, on réunit la plupart des fonctions qui me paraissent
importantes, mais je pense qu’il y a encore moyen de faire beaucoup pour
s’affranchir des modèles classiques et établis de lecteurs <span class="caps">RSS</span> et
proposer quelque chose d’innovant, misant sur l’ergonomie et s’adressant
au plus grand nombre.</p>
<p>Je vais essayer de mettre ça en pratique, en gardant en tête les points
que je juge le plus important : facilité d’utilisation, ergonomie, beau
et performant. Je ferai sûrement quelques articles sur des points
spécifiques que je croiserai. Si vous me lisez et que vous avez un
hébergement mutualisé, n’hésitez pas à me donner des infos sur votre
hébergement <span class="caps">PHP</span> (version de <span class="caps">PHP</span>, modules disponibles qui sont trouvables
dans le phpinfo notamment) car je ne sais pas exactement quelles sont
les installations typiques de <span class="caps">PHP</span> sur mutualisé.</p>
<p>Enfin, beaucoup de fonctionnalités seraient implémentées très facilement
en utilisant les technos à la mode, nodejs ou les solutions à base de
python par exemple. Mais cela oblige à se priver du côté « facilement
installable par tous » car ces solutions ne sont pas disponibles sur la
plupart des hébergeurs mutualisés. Ça semble aussi être un des problèmes
de <a href="https://diasporafoundation.org/">Diaspora*</a> par exemple, car
j’entends régulièrement qu’<a href="http://maniatux.fr/index.php?article473/diaspora-c-est-pas-pour-moi">installer son pod est
compliqué</a>,
notamment car Diaspora* utilise Ruby, C’est vrai, et si c’est pour
utiliser un pod public, proposé par la communauté, beaucoup
d’utilisateurs ne voient pas de réelles différences par rapport à Facebook,</p>Quelques astuces pour Arduino2014-07-02T22:15:00+02:002014-07-02T22:15:00+02:00Phykstag:localhost,2014-07-02:/Blog/output/2014/07/quelques-astuces-pour-arduino.html<p>Voici astuces en vrac pour Arduino que j’ai découvertes ces derniers jours, en
codant pour <a href="http://citizenwatt.paris/">CitizenWatt</a> et en particulier pour le
<a href="https://github.com/CitoyensCapteurs/CitizenWatt-sensor">capteur</a>.</p>
<h2>Stocker des données en Flash</h2>
<p>Il peut arriver d’avoir pas mal de données statiques dans un programme et donc
d’arriver à court de <span class="caps">RAM</span> disponible …</p><p>Voici astuces en vrac pour Arduino que j’ai découvertes ces derniers jours, en
codant pour <a href="http://citizenwatt.paris/">CitizenWatt</a> et en particulier pour le
<a href="https://github.com/CitoyensCapteurs/CitizenWatt-sensor">capteur</a>.</p>
<h2>Stocker des données en Flash</h2>
<p>Il peut arriver d’avoir pas mal de données statiques dans un programme et donc
d’arriver à court de <span class="caps">RAM</span> disponible (2ko sur un ATMega 328p / Arduino Uno). Et
quand ça arrive, c’est le drame (typiquement, le Serial se mettait à faire
n’importe quoi dans mon cas)…</p>
<p>Par exemple, à chaque appel de <code>Serial.println("Quelque chose");</code>, la chaîne
de caractères <code>"Quelque chose"</code> est chargée en <span class="caps">RAM</span>. Du coup, sur un code assez
long, avec pas mal d’affichage verbeux sur la liaison série, on sature vite la
<span class="caps">RAM</span>.</p>
<p>Qu’à cela ne tienne, il est possible de stocker la chaîne dans la Flash et de
la charger directement depuis la Flash. Avant, c’était compliqué, il fallait
utiliser <code>PROGMEM</code>, mais depuis la version 1.0 de l’<span class="caps">IDE</span>, il suffit d’entourer
la chaîne de <code>F()</code>, par exemple <code>Serial.println(F("Quelque chose"));</code>.
<a href="http://playground.arduino.cc/Learning/Memory">Source</a></p>
<p>Et au passage, <a href="http://playground.arduino.cc/Code/AvailableMemory">un petit bout de
code</a> pour savoir combien
il reste de <span class="caps">RAM</span> disponible.</p>
<h2>Les préférences de l’<span class="caps">IDE</span></h2>
<p>Je n’avais jamais été faire un tour dans les préférences de l’<span class="caps">IDE</span> non plus,
principalement par flemme. Qu’à cela ne tienne, c’est désormais chose faite,
et j’y ai croisé quelques options vraiment vitales.</p>
<p>En particulier, “Afficher les résultats détaillés pendant compilation” qui
permettra d’avoir un <em>output</em> plus verbeux pendant la compilation.</p>
<p>Mais la vraie révélation de cette soirée, c’est l’option “Utiliser un éditeur
externe”. Vous ne supportez plus l’éditeur Arduino et son indentation pourrie,
ses fonctionnalités dignes de <em>notepad</em> premier du nom et son non affichage
des numéros de ligne (à part en bas dans un petit coin, inutilisable au
possible pour débugger efficacement), cette option est faite pour vous ! En
l’activant, Arduino ne lira plus le fichier. Vous pouvez l’éditer comme vous
voulez dans un éditeur externe (Vim <3) et au moment d’<em>uploader</em> le code,
l’<span class="caps">IDE</span> Arduino ira relire le fichier, le compiler et l’<em>uploader</em>.</p>Interruptions possibles de service dans les prochains jours2014-04-12T16:30:00+02:002014-04-12T16:30:00+02:00Phykstag:localhost,2014-04-12:/Blog/output/2014/04/interruptions-possibles-de-service-dans-les-prochains-jours.html<p>Je vais changer mon serveur kimsufi que j’ai depuis 1 an, pour un
nouveau de la gamme 2013, largement plus puissant pour le même prix. Du
coup, je vais tout transférer sur la nouvelle machine (mufasa.phyks.me)
dans les prochains jours, et, me connaissant, je vais sûrement rater …</p><p>Je vais changer mon serveur kimsufi que j’ai depuis 1 an, pour un
nouveau de la gamme 2013, largement plus puissant pour le même prix. Du
coup, je vais tout transférer sur la nouvelle machine (mufasa.phyks.me)
dans les prochains jours, et, me connaissant, je vais sûrement rater un
truc :)</p>
<p>Du coup, il se peut que vous rencontriez quelques difficultés à accéder
à mon site dans les prochains jours. J’éditerai cet article quand tout
sera migré.</p>
<p>Update (13/04, 17h33) : Migration terminée. Tout s’est bien passé en
fait, et je ne crois pas avoir eu d’interruption de service (à part
<a href="http://git.phyks.me">git.phyks.me</a> pendant quelques heures).</p>Timeline.js, une lib pour tracer des graphes en JavaScript2014-04-09T23:52:00+02:002014-04-09T23:52:00+02:00Phykstag:localhost,2014-04-09:/Blog/output/2014/04/timelinejs-une-lib-pour-tracer-des-graphes-en-javascript.html<p>Pour <a href="http://citizenair.io/">un projet</a> (dont je reparlerai sûrement
bientôt, au passage), j’ai eu besoin de tracer des graphes en
JavaScript. Le moyen le plus simple, sachant qu’en plus j’avais besoin
d’un peu d’interactivité, était d’utiliser du <span class="caps">SVG</span> et de le générer
directement en JavaScript.</p>
<p>J …</p><p>Pour <a href="http://citizenair.io/">un projet</a> (dont je reparlerai sûrement
bientôt, au passage), j’ai eu besoin de tracer des graphes en
JavaScript. Le moyen le plus simple, sachant qu’en plus j’avais besoin
d’un peu d’interactivité, était d’utiliser du <span class="caps">SVG</span> et de le générer
directement en JavaScript.</p>
<p>J’ai donc pensé utiliser une bibliothèque déjà écrite… et c’est là que
le bât blesse… On trouve de très bonnes bibliothèques, pour faire de
très beaux graphes avec des animations et tout et tout, mais <strong>rien</strong> de
léger, simple et fonctionnel. Je voulais juste tracer des graphes en <span class="caps">SVG</span>
(potentiellement plusieurs superposés) et avoir des actions
personnalisables au clic sur un point. Pas d’animations, ça ne sert à
rien, pas de tracés de multiples objets différents en <span class="caps">SVG</span>, juste des
graphes… Alors, pourquoi charger 30ko de jQuery <strong>plus</strong> minimum 10ko de
Javascript supplémentaires (ça c’était uniquement pour la plus légère,
la moyenne était plutôt autour de 70ko supplémentaires) juste pour faire
ça ?!?</p>
<p>Du coup, j’ai écrit une petite bibliothèque JavaScript <span class="caps">KISS</span> pour tracer
des graphes en <span class="caps">SVG</span>. Vous pouvez mettre autant de graphes que vous
voulez, spécifier le remplissage souhaité, le type de tracé souhaité, et
comme c’est du <span class="caps">SVG</span>, c’est très simple de <em>binder</em> des événements
JavaScript sur vos points (la bibliothèque supporte du clic par défaut,
et il y a une petite animation au survol avec une légende). Le tout pour
23ko non compressé (soit moins que jQuery seule, soit dit en passant),
et 15ko une fois minifiée, sans aucune dépendance externe. Ça devrait
marcher sans problème sur tous les navigateurs décents (pas de fallback
compliqué sur du canvas ou autre implémenté par contre) et on peut même
descendre sous les 10ko en obfuscant un peu le code.</p>
<p>Voilà, je ne sais pas si ça servira à quelqu’un, mais on sait jamais. Du
coup, si ça vous intéresse, <a href="https://github.com/phyks/timeline.js">ça se récupère ici sur
Github</a> et il y a mêmes quelques
exemples de démos <a href="http://phyks.github.io/timeline.js/">ici</a>. Le code
n’est sûrement pas parfait, mais ça devrait être fonctionnel (et
n’hésitez pas à signaler les issues que vous rencontrez). Comme
toujours, c’est sous licence <em><span class="caps">SODAWARE</span></em> : en gros, vous en faites ce que
vous voulez, comme vous voulez, mais c’est quand même cool de dire où
vous l’avez trouvé (et c’est quand même vraiment pas cool de
s’approprier le travail des autres…) et si vous trouvez ma petite
bibliothèque utile / fun / cool / whatever et que par hasard on se
croise (ou non), vous pouvez me payer un soda (ou plus) :). Et surtout,
n’hésitez pas à faire des pull requests ou à me faire signe si vous vous
en servez, que je vois tout ce qu’on peut faire avec :)</p>Retour sur mon fairphone2014-03-01T17:43:00+01:002014-03-01T17:43:00+01:00Phykstag:localhost,2014-03-01:/Blog/output/2014/03/retour-sur-mon-fairphone.html<p>J’ai acheté un <a href="http://fairphone.com/">Fairphone</a> en novembre, et je l’ai reçu
il y a quelques semaines maintenant. Je n’ai pas encore eu le temps d’écrire
dessus, mais c’est désormais corrigé. Ce Fairphone vient remplacer mon ancien
Galaxy S3, qui tournait sous Cyanogen 9, mais qui n …</p><p>J’ai acheté un <a href="http://fairphone.com/">Fairphone</a> en novembre, et je l’ai reçu
il y a quelques semaines maintenant. Je n’ai pas encore eu le temps d’écrire
dessus, mais c’est désormais corrigé. Ce Fairphone vient remplacer mon ancien
Galaxy S3, qui tournait sous Cyanogen 9, mais qui n’a pas arrêté de me poser
des problèmes (problème avec la puce son qui se coupait parfois, présent chez
de nombreux utilisateurs apparemment, entre autres).</p>
<p>Note : Ceci est un petit compte-rendu après quelques semaines d’utilisation.
Je mettrai cet article à jour au fur et à mesure, si de nouveaux problèmes
apparaissent ou sont, au contraire, résolus.</p>
<p><a href="http://localhost/Blog/output/images/2014/03/fairphone_1.jpg"><img alt="Face
avant" src="http://localhost/Blog/output/images/2014/03/fairphone_1.jpg"></a><a href="http://localhost/Blog/output/images/2014/03/fairphone_5.jpg"><img alt="Face
arrière" src="http://localhost/Blog/output/images/2014/03/fairphone_5.jpg"></a></p>
<h2>Un Fairphone ?</h2>
<p>Tout d’abord, qu’est-ce que c’est que cette étrange bête ? Fairphone est une
initiative d’un groupe de hollandais pour proposer une alternative plus
équitable aux smartphones actuels. Le projet a été crowdfundé pendant un peu
plus d’un an, et le premier lot de 25 000 Fairphones a été livré en janvier.</p>
<p>Ils se sont engagés sur un certain nombre de points, parmi lesquels :</p>
<ul>
<li>Transparence, ils communiquent précisément sur ce que contient leur
téléphone, sur les coûts et il y a notamment <a href="http://www.fairphone.com/wp-content/uploads/2013/09/Fairphone_Cost_Breakdown_and_Key_Sept2013.pdf">une infographie
disponible</a>
pour détailler le prix du téléphone.</li>
<li>Ils ont dans la mesure du possible essayé d’avoir un produit plus
équitable que ce qui existe aujourd’hui. En particulier, leurs
fournisseurs s’engagent sur un certain nombre de points (conditions de
travail dans les usines en Chine, non soutien aux guerillas liées au
commerce de métaux précieux en Afrique…). Il n’a pas toujours été possible
de faire ce qu’ils espéraient (ils sont par exemple obligés de produire en
Chine, même s’ils auraient voulu avoir un produit européen), mais ils ont
bien respectés leurs engagements dans l’ensemble.</li>
<li>Libération des <em>datasheets</em> et des logiciels. C’est là un point très
compliqué dans le monde du mobile. En effet, le secteur de la téléphonie
mobile est un des secteurs les plus <em>closed source</em> qui existe, et il est
très difficile de faire bouger ça. Ils ont essayer de convaincre leurs
fournisseurs de diffuser certaines <em>datasheets</em>, mais ce n’est pas facile,
et je ne crois pas qu’ils aient beaucoup réussi à faire bouger les choses
de ce côté-là. En revanche, leurs logiciels sont open source et ils
livrent le Fairphone avec un Android stock, sans applications Google
préinstallées, ce qui est un très bon point par rapport aux autres
fabricants. Ils ont également dit qu’ils soutiendraient le port de Firefox
<span class="caps">OS</span> sur le Fairphone si des développeurs voulaient y travailler (mais
qu’ils ne pourraient pas l’assurer eux-mêmes).</li>
</ul>
<p>Finalement, on a un smartphone assez similaire au Wiko Cink Five, il me
semble, pour 325€, ce qui est certes plus cher, mais n’avance pas les mêmes
atouts. Voyons voir ce que vaut le Fairphone après quelques semaines d’utilisation.</p>
<h2>Ergonomie et design</h2>
<p>Le Fairphone a un écran de 4”3. Ce n’est pas tant que ça pour un smartphone
actuel (on est plus autour de 5” aujourd’hui), mais au moins ça rentre dans
une poche. Quand je le compare à mon ancien Galaxy S3, il paraît tout petit.
De nombreuses personnes préfèrent avoir un grand écran, mais quitte à avoir
des écrans de 5” et plus, autant prendre une tablette. En fait, ces tailles me
paraissent un peu bancales, à mi-chemin entre un téléphone et une tablette :
pas facile à prendre en main d’une seule main, trop petit pour deux mains, pas
pratique dans une poche… Finalement, je suis plutôt favorable à une diagonale
plus petite. À titre de comparaison, c’est à peu près la même diagonale
d’écran que l’iPhone 5 (4”) et il a la même taille à quelques millimètres près.</p>
<p>Le design est plutôt soigné et l’appareil est assez joli, avec son liseret
blanc et son dos en alu. On notera la présence d’un bouton “Marche/Arrêt”
classique au sommet de l’appareil et un bouton de réglage du volume sur le
côté. Les trois boutons en façade (Menu / Accueil / Retour) sont en fait des
touches tactiles. Elles sont assez jolies, mais on a tendance à les effleurer
par inadvertance en tapant des messages. On s’y habitue, mais je préfère
clairement avoir des boutons physiques à cet endroit.</p>
<p>Pour une fois, le capot arrière s’enlève assez facilement, contrairement à de
nombreux smartphones avec lesquels on a peur de briser la fine couche de
plastique qui sert de capot arrière. Derrière, on trouve deux logements pour
carte <span class="caps">SIM</span> (<span class="caps">SIM</span> classique, et non micro-<span class="caps">SIM</span>, on dirait que la mode des toutes
petites <span class="caps">SIM</span> est passée ?), l’emplacement de la batterie et un emplacement
Micro-<span class="caps">SD</span> pour étendre le stockage de 16Go initial.</p>
<p>Un point négatif quand même : l’appareil photo est légèrement sortant du
téléphone. Du coup, quand le téléphone est posé à plat sur une table, il
repose sur l’appareil photo, et sur un des coins, mais il manque un troisième
point d’appui au même niveau. Conclusion : il est bancal quand il est posé sur
une table. C’est dommage car ce n’est vraiment pas grand chose, mais ça
complique grandement son utilisation d’une seule main, en le posant sur une table.</p>
<p><a href="http://localhost/Blog/output/images/2014/03/fairphone_7.jpg"><img alt="Vue de
côté" src="http://localhost/Blog/output/images/2014/03/fairphone_7.jpg"></a></p>
<h2>Écran</h2>
<p>L’écran est de plutôt bonne qualité, avec une bonne résolution (960x540
pixels, pour une densité de 256ppi), similaire au Wiko Cink Peax 2. J’ai eu
auparavant un iPhone 4 et un Galaxy S3 et la qualité de l’écran ne me perturbe
pas particulièrement (ni en bien, ni en mal), mais mon utilisation n’est peut
être pas la plus propice pour juger de la qualité de l’écran ? Je n’ai pas eu
l’occasion de le comparer côte à côte avec mon Galaxy (notamment parce qu’avec
un écran cassé, le rendu n’aurait pas été à son avantage), donc je ne peux pas
en dire beaucoup plus…</p>
<p>En parlant d’écran cassé, l’écran a également une vitre “Gorilla Glass” censée
être assez résistante. Ceci dit, cela n’a pas empêché la vitre de mon Galaxy
de s’exploser à la moindre chute de 10cm avec une coque de protection :/</p>
<p>Une remarque quand même : l’écran a tendance à garder pas mal les traces de
doigt. Plus que le <span class="caps">SGS3</span> en tout cas je dirais.</p>
<p>Un autre point important à noter, pour ne pas être surpris, est la présence
d’un réseau de petits points sur l’écran, que l’on voit sous certaines
conditions d’éclairage. C’est un peu perturbant au début, car on commence par
en voir un, et on pense à un pixel mort. Puis on en voit d’autres, et on finit
par se rendre compte qu’ils sont trop bien alignés pour que ce soit un
problème. Finalement, on trouve la réponse sur le <a href="https://fairphone.zendesk.com/hc/communities/public/questions/200680167-Touch-screen-grid-visible-">forum de support
Fairphone</a> :
il s’agit d’une grille pour l’écran tactile, qui est visible sous certaines
conditions d’éclairage. Ils ont dû adopter cette technologie à cause d’un
brevet sur les autres solutions. Personnellement, je n’y fais pas
particulièrement attention et cela ne me dérange pas et on ne le voit que sous
certaines conditions bien particulières (donc pas dérangeant pour des vidéos a
priori), mais il faut le savoir pour ne pas être surpris.</p>
<h2>Système</h2>
<p>Le Fairphone tourne sous une version stock d’Android 4.2.2. Par défaut, aucune
application Google n’est installée (libre à vous de les installer au besoin).
Personnellement, venant de Cyanogen Mod sur mon Galaxy S3, je suis resté sans
applications Google et trouve tout ce dont j’ai besoin sur F-Droid. Les seules
applications préinstallées sont :</p>
<ul>
<li>Une application pour <a href="http://www.ifixit.com/">iFixIt</a></li>
<li>Un launcher un peu différent (FairphoneHome)</li>
<li>Un widget pour couper le téléphone (passage en mode avion) pendant un
certain temps à définir (“Profitez d’un moment de tranquillité”), appelé
Peace Of Mind.</li>
<li>Une application pour mettre à jour le système <span class="caps">OTA</span>, et profiter des
corrections de bug apportées par Fairphone.</li>
</ul>
<p>Tous ces logiciels sont open-source, iFixIt étant disponible sur F-Droid et
les autres étant disponibles sur
<a href="https://github.com/Kwamecorp/Fairphone">Github</a>. Je vous laisse d’ailleurs
aller voir le dépôt Github pour plus d’images de l’interface et des widgets.</p>
<p>On a donc un système Android de base, avec une très légère surcouche, le tout
étant open-source, ce qui est très rare sur les smartphones actuels. Pas
d’autres bloatwares que ceux dans Android d’origine donc.</p>
<p>La légère surcouche graphique est très jolie, et va plutôt bien avec le look
du Fairphone, à mon avis. Cf <a href="http://lehollandaisvolant.net/?d=2013/10/07/14/09/21-pourquoi-le-flat-design-tel-quil-est-utilise-actuellement-sux">cet article sur le flat design chez le
hollandais
volant</a>,
je trouve que le Fairphone n’en est pas trop victime.</p>
<p><a href="http://localhost/Blog/output/images/2014/03/fairphone_2.jpg"><img alt="Écran" src="http://localhost/Blog/output/images/2014/03/fairphone_2.jpg"></a><a href="http://localhost/Blog/output/images/2014/03/fairphone_6.jpg"><img alt="Batterie" src="http://localhost/Blog/output/images/2014/03/fairphone_6.jpg"></a></p>
<p>Un des changements apportés par la surcouche graphique est la présence d’un
lanceur rapide lorsqu’on touche le bord droit de l’écran (uniquement sur
l’écran d’accueil et sur le menu des applications). C’est d’ailleurs grâce à
lui qu’on accède à la liste des applications. Il est assez pratique, une fois
qu’on s’y est un peu habitué. En effet, au début, on l’appelle souvent sans
faire exprès en naviguant dans la liste des applications.</p>
<p><a href="http://localhost/Blog/output/images/2014/03/fairphone_3.jpg"><img alt="Homescreen" src="http://localhost/Blog/output/images/2014/03/fairphone_3.jpg"></a><a href="http://localhost/Blog/output/images/2014/03/fairphone_4.jpg"><img alt="Homescreen" src="http://localhost/Blog/output/images/2014/03/fairphone_4.jpg"></a></p>
<p><span class="caps">P.S.</span>: Parmi les applications de base, on trouve également une application
“<span class="caps">TODO</span>”, un enregistreur de son, une application pour écouter la radio <span class="caps">FM</span>, une
application de notes et un gestionnaire de fichier. Me corriger si je me
trompe, mais il me semble que ces applications sont intégrées à Android stock.</p>
<h2>Appareil photo</h2>
<p>L’appareil photo me semble raisonnable, même si j’avoue ne pas avoir beaucoup
de références en la matière. Par contre, l’application n’arrêtait pas de
m’afficher le tutoriel. En fait, il suffit de le suivre en entier (ce qui
prend environ 30 secondes), et ensuite vous ne le verrez plus. Sinon, vous
pouvez aussi installer l’application Camera stock disponible sur f-droid.</p>
<p>Pour juger plus en détails de la qualité des photos, je vous laisse regarder
les photos disponibles <a href="http://phyks.me/images/2014/03/photos_fairphone/">ici</a>
que j’ai prises avec mon fairphone.</p>
<h2>Quelques problèmes rencontrés</h2>
<h3><span class="caps">GPS</span></h3>
<p>Comme pour de nombreux utilisateurs, le premier fix <span class="caps">GPS</span> a été très long à
avoir. En fait, je n’ai même pas réussi à l’avoir en intérieur… Mais en
activant l’A-<span class="caps">GPS</span>, en téléchargeant les données <span class="caps">EPO</span> et en faisant un petit tour
à pied dehors, le fix <span class="caps">GPS</span> est assez rapide (< 5 minutes). Une fois ce
premier fix réalisé, mon <span class="caps">GPS</span> se fixe quasiment instantanément (< 10
secondes). Voir notamment <a href="http://forum.xda-developers.com/wiki/Fairphone_Fairphone/Guides#How_to_improve_the_GPS_signal">cette
page</a>
chez xda-developpers et <a href="https://fairphone.zendesk.com/hc/communities/public/questions/200690467--Searching-for-GPS-">ce
thread</a>
sur le forum fairphone pour plus d’informations.</p>
<h3>Gestion des cartes <span class="caps">SIM</span></h3>
<p>La gestion des cartes <span class="caps">SIM</span> diffère un peu de ce que j’avais sur mon Galaxy S3.
En particulier, le Fairphone a deux emplacements <span class="caps">SIM</span>, et vous affichera donc
une notification si vous n’en avez qu’une seule d’insérée. De plus, à chaque
sortie du mode avion, votre code <span class="caps">PIN</span> vous sera demandé (alors que mon Galaxy
S3 ne le demandait qu’une fois par démarrage du téléphone). Enfin, étant chez
Free, je suis souvent en itinérance (nationale, sur le réseau Orange). Le
Fairphone ne fait aucune différence entre l’itinérance nationale et
internationale, et vous aurez donc droit à quelques messages vous prévenant
que vous êtes en itinérance sur la carte <span class="caps">SIM</span> utilisée et vous demandant de
confirmer l’envoi d’un <span class="caps">SMS</span> (par exemple). Il est possible de désactiver les
confirmations répétées, et il ne restera alors plus qu’une seule alerte à
l’envoi d’un <span class="caps">SMS</span> à la sortie du mode avion. Il faut également penser à
désactiver l’itinérance quand on est à l’étranger du coup, pour éviter les surcoûts.</p>
<p>Je n’ai pas encore eu l’occasion de tester le téléphone avec deux SIMs à la
fois, mais a priori c’est très classique. On peut spécifier les cartes SIMs
par défaut à utiliser, et la carte <span class="caps">SIM</span> utilisée apparaît en encart dans chaque
<span class="caps">SMS</span>, etc. Je devrais pouvoir le tester d’ici un mois je pense, je mettrai à
jour l’article en conséquence.</p>
<h3>Divers problèmes</h3>
<ul>
<li>J’ai eu droit à quelques reboots de l’interface en utilisant Firefox
(notamment en utilisant des pages webRTC, qui sont assez lourdes). Rien de
bien méchant, et je ne sais pas en fait si cela vient du Fairphone ou de firefox.</li>
<li>J’ai eu droit une fois à un blocage complet (écran éteint, bouton
marche/arrêt sans effet). J’ai du redémarrer le téléphone en restant
longtemps appuyé sur le bouton marche/arrêt, mais je ne sais pas
exactement ce qu’il s’est passé.</li>
<li>Quelques bugs de traductions. En particulier, “reboot” n’est pas traduit
en “redémarrer”, et de temps à autres l’application de <span class="caps">SMS</span> m’affiche “Nom
d’artiste inconnu” au lieu de l’heure du dernier message.</li>
</ul>
<h2>Divers</h2>
<ul>
<li>Toutes les spécifications détaillées sont disponibles
<a href="http://buy-a-phone-start-a-movement.fairphone.com/en/specs/">ici</a>.</li>
<li>Le <span class="caps">DAS</span> du téléphone est assez faible (0.329 W/kg au niveau de la tête,
0.693 W/kg au niveau du corps).</li>
<li>Pas de <span class="caps">NFC</span> intégré. Je n’ai personnellement eu l’occasion d’utiliser le
<span class="caps">NFC</span> de mon Galaxy S3 que pour m’amuser à scanner les badges que j’avais
dans mon portefeuille, donc ce n’est pas un bien grand mal.</li>
<li>Pour éviter de multiplier les chargeurs / écouteurs inutiles, le téléphone
est vendu seul dans sa boîte. En effet, la plupart des gens ont déjà
plusieurs chargeurs et écouteurs chez eux et il est inutile d’en rajouter
un qui traînera au fond d’une armoire. Libre à vous d’en prendre un en
option au besoin.</li>
</ul>
<h2>Conclusion</h2>
<p>En conclusion, je suis très satisfait de mon Fairphone. Il est certes un peu
plus cher que la concurrence, et présente quelques défauts de jeunesse, mais
il me paraît tout à fait raisonnable et une bonne alternative aux autres
téléphones des grands constructeurs. Par contre, étant édité à peu
d’exemplaires, je doute qu’on voit beaucoup d’accessoires dédiés dans les
prochains mois (notamment de housses parfaitement adaptées à son <em>form
factor</em>). Je ne suis pas doué pour les conclusions, donc je vous laisse
conclure tout seul :)</p>
<p>Note (car il faut bien un peu de troll) : on se rappellera des défauts des
problèmes sur les premiers smartphones (et pas que les premiers en fait) des
autres constructeurs, notamment l’absence de 3G sur le premier iPhone, ou
encore les <a href="http://www.iphon.fr/post/2009/06/19/L-iPhone-3G-S-peut-aussi-avoir-la-jaunisse">problèmes d’écran jaune sur l’iPhone
<span class="caps">3GS</span></a>
ou récemment sur <a href="http://www.macbidouille.com/news/2012/09/22/l-iphone-5-a-un-ecran-plus-jaune?iact=rc&dur=349&page=1&start=0&ndsp=50&ved=0CFcQrQMwAA">l’iPhone
5</a>.</p>
<p>Edit : J’ai retrouvé le lien vers l’article sur le site du projet replicant
qui parlait de l’open-source et du Fairphone :
<a href="http://blog.replicant.us/2013/11/fairphone/">http://blog.replicant.us/2013/11/fairphone/</a>.</p>
<p>Edit 2 : J’ai oublié de parler de la batterie et de l’autonomie… C’est donc
réparé avec ce petit rajout. L’autonomie est plutôt bonne, dans la moyenne des
smartphones actuels (en tout cas, sensiblement comparable à celle de mon
ancien S3). Je tiens une journée (8h -> 24h) en relevant 5 comptes e-mails
en push, en allant sur internet dans le bus (1h) et à quelques occasions dans
la journée, et en passant la journée dans une zone pas très bien couverte (je
finis la journée avec entre 10% et 30% de batterie selon les jours). Bref,
comme d’hab’, on tient une journée sans trop de difficulté (sauf utilisation
ultra-intensive, mais pour ça, on ne peut pas grand chose) mais il faut quand
même recharger tous les soirs. En restreignant un peu mon utilisation, je
pense que je pourrais tenir deux jours.</p>
<p>Edit 3 : Le blocage complet et le reboot de l’interface sont liés et sont un
seul et même problème apparemment. Cela arrive aussi avec le contrôle du
volume. Je l’ai eu quelques fois depuis que j’ai mon Fairphone, et c’est assez
embêtant comme bug. Mais Fairphone est au courant et le problème devrait être
corrigé <a href="https://fairphone.zendesk.com/hc/en-us/articles/201804933-When-will-the-new-software-update-1-2-be-available-">dans la prochaine mise à
jour</a>
qui arrivera d’ici peu. De même pour les problèmes <a href="https://fairphone.zendesk.com/hc/en-us/articles/201852278-National-Roaming-Mostly-Solved-">d’itinérance
nationale</a>
qui devraient être résolus bientôt. J’ai également depuis peu une deuxième
carte <span class="caps">SIM</span> et rien à redire sur la gestion des cartes <span class="caps">SIM</span> : on peut choisir la
<span class="caps">SIM</span> par défaut pour chaque action (<span class="caps">SMS</span>, Appels, Internet, …) et la gestion des
deux cartes est très complète. Quand à l’autonomie, je tiens toujours un peu
plus d’une journée avec mon utilisation. Par exemple, ce soir, j’en suis à 15h
sur batterie, 5 comptes e-mails en push toute la journée, une couverture
réseau assez aléatoire et 2 à 3h sur Internet en 3G et il me reste encore 22%
de batterie.</p>
<p>Edit 4 J’ai envoyé un e-mail pour rapporter les issues remarquées à Fairphone
et ils m’ont répondu (avec un peu de retard, mais quand même) qu’ils prenaient
note et corrigeraient. Et Fairphone <a href="http://buy-a-phone-start-a-movement.fairphone.com/en/spareparts/">vend des pièces
détachées</a>
et a mis des guides pour réparer son téléphone.</p>Local notifications for Weechat and UrXVT2014-02-20T20:57:00+01:002014-02-20T20:57:00+01:00Phykstag:localhost,2014-02-20:/Blog/output/2014/02/local-notifications-for-weechat-and-urxvt.html<p>After moving from irssi to weechat, I decided to look for a way to have
local notifications for <span class="caps">IRC</span> messages. The problem is that I run weechat
through a screen on my server, which I access thanks to <span class="caps">SSH</span>. Thus, I
need to find a way to allow weechat to …</p><p>After moving from irssi to weechat, I decided to look for a way to have
local notifications for <span class="caps">IRC</span> messages. The problem is that I run weechat
through a screen on my server, which I access thanks to <span class="caps">SSH</span>. Thus, I
need to find a way to allow weechat to communicate to my local terminal
and send notifications.</p>
<p>I found many solutions on the web which were using a local server or a
pipe file. But these aren’t fitted to my needs, as they need an external
program running on my machine, which I don’t want. I was quite sure
there could be a way to do it, with nothing more than my terminal
emulator and weechat plugins, and I finally found it. My solution is
based on
<a href="http://artisan.karma-lab.net/ajouter-notification-a-urxvt">karma-lab</a>‘s
one [French].</p>
<p>The idea is to use the Bell signal which corresponds to the <span class="caps">ASCII</span> escape
sequence 7 to raise attention (beep signal). The following steps work
fine with UrXVT and weechat in a screen session. It may be possible to
adapt this to other terminal emulators or terminal multiplexers (such as
tmux) but I don’t use them and can’t help you much with it. We will
define our own escape sequence, that will be interpreted by an UrXVT
plugin and will spawn a notification with the <span class="caps">IRC</span> message.</p>
<p>First of all, you will have to modify your <code>~/.Xdefaults</code>
or your <code>~/.Xresources</code> to tell UrXVT to listen for bell
signals. In order to do so, just add the following line:</p>
<div class="highlight"><pre><span></span><code>URxvt*urgentOnBell: true
</code></pre></div>
<p>Then, reload it:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>xrdb<span class="w"> </span>-load<span class="w"> </span>~/.Xdefaults
</code></pre></div>
<p>Your UrXVT terminal now listens to bell signals. But we’d like them to
spawn real local notifications. For this, I used libnotify, which is
built-in in gnome. The main idea is to enhance our bell signal with a
more complete escape sequence to include a message to display (using the
so-called osc sequences). Thus, the sequence sent to UrXVT will look
like <code>\[ESC\]777;notify;TITRE;MESSAGEBELL\]</code>. Just add the
following plugin (written by
<a href="http://artisan.karma-lab.net/ajouter-notification-a-urxvt">Karma-lab</a>[French]
and slightly modified by me to enhance security) to your UrXVT and you
are ready to go. So, you should put <a href="https://pub.phyks.me/scripts/urxvt/notify">this
plugin</a> in
<code>/usr/lib/urxvt/perl/notify</code>.</p>
<p>To test that everything worked correctly, you can use the following command:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span><span class="nb">echo</span><span class="w"> </span>-ne<span class="w"> </span><span class="s2">"\033]777;notify;Moi;Hello World\007\007"</span>
</code></pre></div>
<p>which should spawn an “Hello World” notification on your desktop.</p>
<p>Finally, if the previous example is working fine, let’s integrate it to
Weechat. We’ll need another plugin for weechat, to make him write this
escape sequence when needed to send notifications. This plugin is also
from karma-labs, but as my weechat is running in a <code>screen</code>
session, I had to tweak it a bit. I improved security of the plugin as
well, to prevent any unauthorized code execution. Concerning
<code>screen</code>, it is “consuming” the escape sequences for itself,
and you have to tweak it a bit to make it pass through
<code>screen</code>. The python script to load in your Weechat can be
found <a href="https://pub.phyks.me/scripts/weechat/screen_away.py">here</a>.</p>
<p>Have fun with <span class="caps">IRC</span> and your brand new notifications !</p>Page sur l’autohébergement mise à jour2013-12-25T23:27:00+01:002013-12-25T23:27:00+01:00Phykstag:localhost,2013-12-25:/Blog/output/2013/12/page-sur-lautohebergement-mise-a-jour.html<p>Juste un (très) court article pour signaler que je me suis (enfin)
décidé à vider ma todo-list. En particulier, je viens de reprendre <a href="http://phyks.me/autohebergement.html">ma
page sur l’autohébergement</a> que je
n’avais pas terminée et qui trainait sur mon serveur. J’ai déjà commencé
par rajouter un peu de <span class="caps">CSS …</span></p><p>Juste un (très) court article pour signaler que je me suis (enfin)
décidé à vider ma todo-list. En particulier, je viens de reprendre <a href="http://phyks.me/autohebergement.html">ma
page sur l’autohébergement</a> que je
n’avais pas terminée et qui trainait sur mon serveur. J’ai déjà commencé
par rajouter un peu de <span class="caps">CSS</span>, et rien que ça, ça change tout ! :)</p>
<p>Cette page doit me servir de mémo si j’ai besoin de réinstaller mon
serveur et fournit tout un tas de lien et d’astuces diverses pour
quiconque voudrait se lancer dans l’autohébergement. Je la mettrai à
jour au fur et à mesure des évolutions sur mon serveur et des nouveaux
scripts que je découvrirai.</p>
<p>Cette page va de pair avec les tags
<a href="https://links.phyks.me/?searchtags=AutoH%C3%A9bergement">AutoHébergement</a>
et <a href="https://links.phyks.me/?searchtags=Serveur">Serveur</a> sur <a href="https://links.phyks.me/">mon
shaarli</a>.</p>
<p>En espérant que ça serve à quelqu’un (et puis sinon, tant pis…, ça me
servira toujours à moi :)… (n’ayant <em>volontairement</em> pas de stats sur
mon serveur, je ne sais pas si ça servira à quelqu’un ou pas :)</p>Hilight window in weechat2013-12-25T01:33:00+01:002013-12-25T01:33:00+01:00Phykstag:localhost,2013-12-25:/Blog/output/2013/12/hilight-window-in-weechat.html<p>I recently moved from Irssi+Screen to Weechat+Screen (and I’m planning
to look at weechat interfaces in the future, to have a local irc client
connecting to my server and avoid any latency while typing on low speed
internet connection). My first step was to get almost the …</p><p>I recently moved from Irssi+Screen to Weechat+Screen (and I’m planning
to look at weechat interfaces in the future, to have a local irc client
connecting to my server and avoid any latency while typing on low speed
internet connection). My first step was to get almost the same setup as
irssi. I’m very pleased with what I achieved, and weechat is definitely
an excellent irc client, although it lacks a bit of usable documentation sometimes…</p>
<p>To get something like my old irssi, I had to install some extensions,
including :</p>
<ul>
<li>text_effects.lua to have some inline text decoration such as
*bold* to display bold in bold</li>
<li>buffers.pl to have a list of opened buffers</li>
<li>iset.pl to set configuration options easily</li>
<li>screen_away.py (which is very efficient !) to auto away when I
detach my screen session</li>
</ul>
<p>I extensively used <a href="http://pascalpoitras.com/2013/05/25/my-weechat-configuration/">this
link</a> and
the other articles on weechat on this website, which is a reference in
my opinion, to get a working base weechat configuration.</p>
<p>But, one point that wasn’t documented very well, is the use of a hilight
window without dedicating a buffer to it. Dedicating a buffer to the
hilight window means having an opened buffer in the main window, which
is useless. You always select it accidentally by typing the wrong number
for another buffer, and it’s hidous in your buffer list (even though you
can hide it from there). I don’t know if this could be done in irssi,
but in weechat, you can set highmon to use a bar instead of a buffer to
display the “hilight window” and this is what we’ll see in the
following. I will assume you start with highmon plugin installed and
configured, with a hilight window such as the one from Pascal Poitras.</p>
<p>So, first step is to tell highmon to use a bar for output instead of the
standard buffer :</p>
<div class="highlight"><pre><span></span><code><span class="o">/</span><span class="n">set</span><span class="w"> </span><span class="n">plugins</span><span class="o">.</span><span class="k">var</span><span class="o">.</span><span class="n">perl</span><span class="o">.</span><span class="n">highmon</span><span class="o">.</span><span class="n">output</span><span class="w"> </span><span class="n">bar</span>
</code></pre></div>
<p>Highmon should have created a bar automatically, to put the messages in.
Check weechat.bar.highmon.* options to make sure it did. Next, type :</p>
<div class="highlight"><pre><span></span><code><span class="o">/</span><span class="n">set</span><span class="w"> </span><span class="n">plugins</span><span class="o">.</span><span class="k">var</span><span class="o">.</span><span class="n">perl</span><span class="o">.</span><span class="n">highmon</span><span class="o">.</span><span class="n">bar_lines</span><span class="w"> </span><span class="mi">250</span>
</code></pre></div>
<p>to set the number of lines to be stored in your freshly created bar.</p>
<p>Then, you can edit all the preferences for the bar (size, size_max,
position, priority, hide etc.) as for a standard bar, using
weechat.bar.highmon.* options. Note that priority is important if you
have to bars having the same position. For instance, if two bars are
positioned at the top, the priority property will determine which one is
above the other one.</p>
<p>One last point is that we’d like to have a title for the new hilight bar
(which by default doesn’t have any title). The hack is to use another
plugin, text_item.py to display a bar with some text. To make a title
“[Hilight Monitor]”, just run (after having installed text_item.py):</p>
<div class="highlight"><pre><span></span><code><span class="o">/</span><span class="n">set</span><span class="w"> </span><span class="n">plugins</span><span class="p">.</span><span class="n">var</span><span class="p">.</span><span class="n">python</span><span class="p">.</span><span class="n">text_item</span><span class="p">.</span><span class="n">hilight_monitor_title_text</span><span class="w"> </span><span class="n">all</span><span class="w"> </span><span class="s">"[Hilight Monitor]"</span>
<span class="o">/</span><span class="n">bar</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="n">highmon_title</span><span class="w"> </span><span class="n">top</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">hilight_monitor_title_text</span>
</code></pre></div>
<p>And play with the position, priority and colors for the newly created
bar to have a nice setup :)</p>
<p>One last important thing is that, contrary to the buffer solution, you
won’t be able to clean easily the hilight window and to scroll in it.
But, I found two aliases on #weechat (ty @silverd for the aliases) that
you can bind to any key if you want:</p>
<div class="highlight"><pre><span></span><code><span class="o">/</span><span class="n">alias</span><span class="w"> </span><span class="n">clear_highmon</span><span class="w"> </span><span class="o">/</span><span class="n">mute</span><span class="w"> </span><span class="o">/</span><span class="n">set</span><span class="w"> </span><span class="n">plugins</span><span class="o">.</span><span class="k">var</span><span class="o">.</span><span class="n">perl</span><span class="o">.</span><span class="n">highmon</span><span class="o">.</span><span class="n">bar_lines</span><span class="w"> </span><span class="o">-</span><span class="mi">1</span><span class="p">;</span><span class="o">/</span><span class="n">mute</span><span class="w"> </span><span class="o">/</span><span class="n">set</span><span class="w"> </span><span class="n">weechat</span><span class="o">.</span><span class="n">bar</span><span class="o">.</span><span class="n">highmon</span><span class="o">.</span><span class="n">items</span><span class="w"> </span><span class="s2">""</span><span class="p">;</span><span class="o">/</span><span class="n">mute</span><span class="w"> </span><span class="o">/</span><span class="n">set</span><span class="w"> </span><span class="n">weechat</span><span class="o">.</span><span class="n">bar</span><span class="o">.</span><span class="n">highmon</span><span class="o">.</span><span class="n">items</span><span class="w"> </span><span class="s2">"highmon"</span><span class="p">;</span><span class="o">/</span><span class="n">mute</span><span class="w"> </span><span class="o">/</span><span class="n">set</span><span class="w"> </span><span class="n">plugins</span><span class="o">.</span><span class="k">var</span><span class="o">.</span><span class="n">perl</span><span class="o">.</span><span class="n">highmon</span><span class="o">.</span><span class="n">bar_lines</span><span class="w"> </span><span class="mi">250</span>
<span class="o">/</span><span class="n">alias</span><span class="w"> </span><span class="n">scroll_highmon_down</span><span class="w"> </span><span class="o">/</span><span class="n">bar</span><span class="w"> </span><span class="n">scroll</span><span class="w"> </span><span class="n">highmon</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">y</span><span class="o">+</span><span class="mi">100</span><span class="o">%</span>
<span class="o">/</span><span class="n">alias</span><span class="w"> </span><span class="n">scroll_highmon_up</span><span class="w"> </span><span class="o">/</span><span class="n">bar</span><span class="w"> </span><span class="n">scroll</span><span class="w"> </span><span class="n">highmon</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">y</span><span class="o">-</span><span class="mi">100</span><span class="o">%</span>
</code></pre></div>
<p>You can now clear the hilight window with /clear_highmon and scroll in
it with the other aliases. So, I think you are good to go for a (quite)
perfect weechat setup :)</p>
<p><strong>Update:</strong></p>
<ul>
<li>
<p>You can define your own keyboard shortcut in the following way:</p>
<p><code>/key bind KEY /scroll_highmon</code></p>
<p>where <span class="caps">KEY</span> is some key or combination of key (for instance
meta-meta2-A or whatever you want). You can do the same for
<code>/clear_highmon</code> and
<code>/scroll_highmon_up</code>.</p>
</li>
<li>
<p>By default, the highmon bar won’t autoscroll. To enable autoscroll,
you should set
<code>plugins.var.perl.highmon.bar_scrolldown</code> to
<code>on</code>.</p>
</li>
</ul>Papa Nawel surprise des shaarlieurs2013-12-24T18:00:00+01:002013-12-24T18:00:00+01:00Phykstag:localhost,2013-12-24:/Blog/output/2013/12/papa-nawel-surprise-des-shaarlieurs.html<p>J’ai participé à l’iniative de Yome <a href="http://yome.ch/papa-nawel-surprise-des-shaarlieurs/">Papa Nawel des
shaarlieurs</a> et
j’ai reçu mon cadeau aujourd’hui de <a href="http://book.knah-tsaeb.org/">Knah
Tsaeb</a>, après quelques déboires avec la Poste.</p>
<p>Il m’a offert six humble bundle. Je connaissais de nom, mais je n’ai
encore jamais expérimenté les humble bundle …</p><p>J’ai participé à l’iniative de Yome <a href="http://yome.ch/papa-nawel-surprise-des-shaarlieurs/">Papa Nawel des
shaarlieurs</a> et
j’ai reçu mon cadeau aujourd’hui de <a href="http://book.knah-tsaeb.org/">Knah
Tsaeb</a>, après quelques déboires avec la Poste.</p>
<p>Il m’a offert six humble bundle. Je connaissais de nom, mais je n’ai
encore jamais expérimenté les humble bundle, ça sera l’occasion ! Merci
beaucoup à toi, Knah Tsaeb !</p>
<p>Du coup, j’en profite pour faire un petit article avec le déballage :)</p>
<p>Avant :
<a href="http://localhost/Blog/output/images/2013/12/nawel_shaarli.png"><img alt="Déballage,
avant" src="http://localhost/Blog/output/images/2013/12/nawel_shaarli.png"></a></p>
<p>Après :
<a href="http://localhost/Blog/output/images/2013/12/nawel_shaarli2.png"><img alt="Déballage,
avant" src="http://localhost/Blog/output/images/2013/12/nawel_shaarli2.png"></a></p>Libre et difficultés2013-12-10T18:00:00+01:002013-12-10T18:00:00+01:00Phykstag:localhost,2013-12-10:/Blog/output/2013/12/libre-et-difficultes.html<p>J’ai récemment vu passer <a href="http://www.slate.fr/monde/80483/nous-avons-tue-notre-internet">cet article de
slate.fr</a>
(Notre Mai-68 numérique est devenu un grille-pain fasciste) sur quelques
shaarlis et <a href="http://alias.codiferes.net/wordpress/index.php/eloge-funebre-dun-internet-libre-et-ouvert-par-son-assassin/">cet autre
article</a>
(Éloge funèbre d’un Internet libre et ouvert, par son assassin) sur le
blog d’alias.</p>
<p>Une phrase dans ce dernier article reprend une idée …</p><p>J’ai récemment vu passer <a href="http://www.slate.fr/monde/80483/nous-avons-tue-notre-internet">cet article de
slate.fr</a>
(Notre Mai-68 numérique est devenu un grille-pain fasciste) sur quelques
shaarlis et <a href="http://alias.codiferes.net/wordpress/index.php/eloge-funebre-dun-internet-libre-et-ouvert-par-son-assassin/">cet autre
article</a>
(Éloge funèbre d’un Internet libre et ouvert, par son assassin) sur le
blog d’alias.</p>
<p>Une phrase dans ce dernier article reprend une idée classique selon
laquelle le libre n’est qu’un “truc de barbus”, qu’il faut déjà faire
partie des barbus pour utiliser un logiciel libre, étant donné
l’attention portée à l’interface, etc.</p>
<blockquote>
<p>Mais je reste persuadé que, pour cela, il va falloir faire changer
beaucoup de mentalités: d’une part, celle des utilisateurs, qu’ils
prennent conscience du danger des systèmes fermés et centralisés, mais
aussi des communautés hacker/open-source, qui doivent faire de gros
efforts de simplification et de pédagogie pour faire des produits que
même les plus technophobes voudront utiliser.</p>
</blockquote>
<p>Personnellement (et de toutes façons, ce billet ne sera qu’un avis
personnel sur la question), je l’avoue, je n’aime pas développer
d’interface. Je ne suis pas un fabuleux <em><span class="caps">UI</span> designer</em> et une fois que
j’ai un code fonctionnel, j’admet volontiers que j’ai tendance à m’en
désintéresser, étant capable de l’utiliser et n’ayant pas le temps de
développer plus le côté <em>user-friendly</em>. C’est certainement dommage,
mais ce n’est pas ce qui m’intéresse… Mais ce n’est pas le cas de
toute la communauté du libre, heureusement.</p>
<p>Ainsi, on peut citer la fondation Mozilla qui a voulu (et a réussi à !)
conquérir les Mme Michu avec son navigateur open-source : Firefox. De
même, LibreOffice fonctionne très bien et est de plus en plus adopté par
des gens qui ne sont pas technophiles du tout.</p>
<p>En revanche, en s’engageant dans cette voie et en cherchant à séduire
Mme Michu à tout prix, on court le risque de simplifier à l’extrême les
développements, afin d’être à la portée de tous. On aboutit alors à une
merveilleuse interface graphique à trois boutons, qui va certes séduire
tout le monde, mais ne couvrira que 0.00(insérer autant de 0 que vous
voulez ici)0001% du logiciel. On pensera notamment à toutes les
surcouches à ffmpeg, qui ne vous apprennent en rien à utiliser ffmpeg,
vous limitent les options disponibles plus qu’autre chose et surtout
vous cache tout ce qui se passe en arrière-plan.Faut-il alors au
contraire garder l’esthétique de la ligne de commande et former
l’utilisateur à utiliser le logiciel, et à comprendre ce qu’il se passe
en arrière-plan ? Pas sûr que ce ne soit une meilleure idée non plus…</p>
<p>La question est également de savoir à quoi vise l’open-source. Le but
est-il de fournir des logiciels adaptés aux <em>end-users</em> ? Vu le travail
à fournir, cela voudrait dire diviser considérablement le nombre de
scripts et de programmes. Ou alors faut-il garder cette multitude de
logiciels et laisser les utilisateurs les plus doués techniquement trier
et adapter ceux qu’ils jugent réellement nécessaires pour tout le monde
? De plus, un logiciel avec une interface graphique rudimentaire, voire
en ligne de commande, laisse transparaître complètement ce qu’il se
passe en arrière-plan. L’utilisateur a un contrôle total sur les actions
du logiciel et peut appréhender l’ensemble des options.</p>
<p>C’est à mon avis un des principaux intérêts de l’open-source : permettre
aux utilisateurs de comprendre comment cela fonctionne et ce qu’il se
passe derrière l’interface graphique. Alors certes, c’est rebutant et
c’est dur au début, mais n’est-ce pas parfaitement réjouissant d’enfin
comprendre comment fonctionne la machine ? J’ai personnellement plus
appris en me débrouillant pour faire fonctionner des logiciels
open-source (mais j’en ai également beaucoup abandonnés faute de
documentation suffisante) qu’en cliquant sur un bouton pour avoir ce que
je voulais (et la plupart des personnes qui découvrent la ligne de
commande, qui commencent à programmer un peu, et qui comprennent alors
réellement ce qu’est vraiment un “bug”, dans mon entourage, me le
confirme). Cliquer sur un bouton ne vous apprendra jamais à vous
débrouiller seul, et ce n’est nullement rendre un service aux
utilisateurs à mon avis. Cliquer sur un bouton pour que ça fonctionne,
c’est pratique à 90% du temps, et ça permet d’aller plus vite sur
certaines actions, mais ce n’est <strong>pas</strong> utiliser son ordinateur à mon
avis, ce n’est qu’utiliser une infime partie des possibilités de
l’ordinateur. (Et ne parlons même pas des cours d‘“informatique” dans
lesquels vous apprenez à utiliser Word… ce n’est <strong>pas</strong> de l’informatique…)</p>
<p>Après, je ne suis pas d’accord sur le fait que la communauté open-source
/ hackers / geeks soit hermétique et fermée. Personnellement, je suis
prêt à passer du temps à aider quiconque voudrait un coup de main, mais
je ne veux pas le faire pour rien. Et le problème est sûrement plutôt de
ce côté-là. Combien d’utilisateurs veulent “juste un système qui marche”
? Combien d’utilisateurs veulent mettre leur cerveau de côté et cliquer
sur des bonbons rigolos et colorés dans un jeu bien connu sur un réseau
social tout aussi connu plutôt que de comprendre ce qu’il se passe
derrière ? Combien d’utilisateurs sont prêts à passer sous Linux en
conchiant les idées et la philosophie associés ? J’avoue que dans ces
situations, j’ai juste l’impression de me faire exploiter, et je n’ai
aucune ambition d’ouvrir un service d’assistance informatique
prochainement. Je pense que le problème est principalement à ce niveau,
entre la différence de compréhension et d’appréhension de l’ordinateur
par les différentes communautés, qui du coup, n’arrivent pas à échanger.</p>
<p>Cf <a href="http://faildesk.net/wp-content/uploads/2011/12/How_users_see_developers.jpg">ce comic parfaitement illustratif :)</a></p>Graver un bootloader sur ATmega82013-12-02T15:02:00+01:002013-12-02T15:02:00+01:00Phykstag:localhost,2013-12-02:/Blog/output/2013/12/graver-un-bootloader-sur-atmega8.html<p>Pour un projet avec mon <em>hacklab</em> <a href="http://hackens.org">hackEns</a>
(éclairage de façades avec des LEDs de puissance, dans la même veine que
<a href="http://www.youtube.com/watch?v=yRxQgc-OKFg">AllColorsAreBeautiful</a> du
<span class="caps">CCC</span>, voir <a href="http://hackens.org/projets/ledhill">cette page</a> pour plus
d’infos), on a eu besoin de graver 30 <em>bootloaders</em> sur des ATmega8. On
n’a pas de programmateur et on le …</p><p>Pour un projet avec mon <em>hacklab</em> <a href="http://hackens.org">hackEns</a>
(éclairage de façades avec des LEDs de puissance, dans la même veine que
<a href="http://www.youtube.com/watch?v=yRxQgc-OKFg">AllColorsAreBeautiful</a> du
<span class="caps">CCC</span>, voir <a href="http://hackens.org/projets/ledhill">cette page</a> pour plus
d’infos), on a eu besoin de graver 30 <em>bootloaders</em> sur des ATmega8. On
n’a pas de programmateur et on le fait donc avec des Arduinos. Comme
toujours, il nous a fallu 2h de debug avant de graver le premier :)
(mais cette fois, ça a été rentable avec 30 <em>bootloaders</em> gravés d’un
coup !).</p>
<p>Du coup, je fais une petite compil’ des liens qui marchent et des trucs
importants à vérifier pour ne pas perdre deux heures (les messages
d’erreur du soft Arduino étant <em>tellement</em> explicites… et il y a 10
méthodes différentes, chacune aboutissant à une erreur différente sur le net).</p>
<p>Tout d’abord, un bon lien qui marche bien :
<a href="http://arduino.cc/en/Tutorial/ArduinoToBreadboard">ArduinoToBreadboard</a>
dans la doc Arduino. Les montages sont clairs et ont été testé par
moi-même ces derniers jours :).</p>
<h2>Gravure de <em>bootloader</em></h2>
<p><a href="http://arduino.cc/en/uploads/Tutorial/BreadboardAVR.png"><img alt="Montage pour graver le
bootloader" src="http://arduino.cc/en/uploads/Tutorial/BreadboardAVR.png"></a>
<a href="http://localhost/Blog/output/images/2013/12/burn.jpg"><img alt="Montage pour graver le bootloader, in
situ" src="http://localhost/Blog/output/images/2013/12/burn.jpg"></a></p>
<h2>Envoi de programmes</h2>
<p><a href="http://localhost/Blog/output/images/2013/12/upload.jpg"><img alt="Montage pour
l'upload" src="http://localhost/Blog/output/images/2013/12/upload.jpg"></a>
<a href="http://localhost/Blog/output/images/2013/12/upload2.jpg"><img alt="Montage pour
l'upload" src="http://localhost/Blog/output/images/2013/12/upload2.jpg"></a></p>
<h2>Notes diverses</h2>
<ul>
<li>Testé avec un Arduino Uno comme programmateur, sans capacités ni
résistances sur les pins de <em>reset</em>. Et ça fonctionne ! Par contre,
on a eu des problèmes avec un Arduino Mega, donc on est resté sur
l’Uno (sans chercher plus, sûrement un problème de <em>reset</em> automatique).</li>
<li>Si ça ne marche pas, vérifier que l’ATmega est bien enfoncé dans la
<em>breadboard</em> ! C’est stupide, mais on oublie une fois sur deux… :)</li>
<li>Hyper important ! Sur le montage pour graver le <em>bootloader</em>, la
résistance au <em>reset</em> est en <em>pull-up</em> (connectée au 5V) et non en
<em>pull-down</em> (connectée au <span class="caps">GND</span>). J’ai perdu 1h là-dessus…</li>
<li>Testé et approuvé avec la dernière version du soft Arduino et du
<em>sketch</em> ArduinoISP. Pas besoin d’une vieille version a priori.</li>
<li>Si ça ne marche toujours pas, bien vérifier le montage, encore et
encore :)</li>
<li>Mieux vaut utiliser le soft Arduino que la ligne de commande avec
avrdude. En effet, Arduino gère tout seul les <em>fuse bits</em>
(utilisation d’un cristal externe, temps de démarrage, protection du
<em>bootloader</em>) et c’est donc moins prise de tête. Sinon, pour les
calculer, c’est <a href="http://www.engbedded.com/fusecalc/">par ici</a> et
<a href="http://treehouseprojects.ca/fusebits/">par ici</a> pour plus d’infos
sur l’utilisation d’un quartz externe.</li>
<li>Lorsque le <em>bootloader</em> est gravé, pour envoyer des programmes
facilement, il faut qu’il puisse <em>reset</em> sur serial (sinon, il faut
faire un <em>reset</em> manuel à chaque fois). Pour ça, il faut mettre une
capacité et une résistance sur le pin de <em>reset</em> (cf schematics des Arduino).</li>
</ul>Decrypt multiple LUKS containers at boot on Arch2013-11-17T08:00:00+01:002013-11-17T08:00:00+01:00Phykstag:localhost,2013-11-17:/Blog/output/2013/11/decrypt-multiple-luks-containers-at-boot-on-arch.html<p>I installed Arch on my laptop with a <span class="caps">LVM</span> on <span class="caps">LUKS</span> setup. But I’ve two
disks on my laptop (so this means at least two <span class="caps">LUKS</span> container) and my
<span class="caps">LVM</span> install extended over the two disks. So, I needed to unlock two
devices at boot to be able to …</p><p>I installed Arch on my laptop with a <span class="caps">LVM</span> on <span class="caps">LUKS</span> setup. But I’ve two
disks on my laptop (so this means at least two <span class="caps">LUKS</span> container) and my
<span class="caps">LVM</span> install extended over the two disks. So, I needed to unlock two
devices at boot to be able to mount my system (which is something the
default encrypt hook doesn’t support in Arch). Here’s a way to proceed
in order to achieve unlocking of multiple encrypted devices (presented
with 2 devices, but can be used for more).</p>
<p>First, you need to install the necessary stuff to use cryptsetup and set
the encrypt hook to be load (in mkinitcpio.conf) as described in <a href="https://wiki.archlinux.org/index.php/Dm-crypt_with_LUKS#.2Fetc.2Fmkinitcpio.conf">Arch
wiki</a>.</p>
<p>Then, copy the file /usr/lib/initcpio/hooks/encrypt to
/usr/lib/initcpio/hooks/encrypt2. Edit this last file and change any
occurrence of cryptdevice and cryptkey by cryptdevice2 and cryptkey2.
Also change the line</p>
<div class="highlight"><pre><span></span><code>mkdir<span class="w"> </span>/ckey
</code></pre></div>
<p>by</p>
<div class="highlight"><pre><span></span><code><span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span>-d<span class="w"> </span>/ckey<span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span>mkdir<span class="w"> </span>/ckey
<span class="k">fi</span>
</code></pre></div>
<p>in order to avoid the display of a warning on boot. Load this encrypt2
hook in your mkinitcpio.conf.</p>
<p>Finally, edit your command line parameters (in Grub for example), adding
the required cryptdevice, cryptkey (for first device) and cryptdevice2,
cryptkey2 (for second device).</p>
<p>This is the best solution I’ve found so far, but it requires to manually
update the second hook when updates are available (cryptsetup package,
not all updates concern encrypt hook). Another solution was provided by
the package cryptsetup-multi but this one is now obsolete and this setup
is the one that works best for me.</p>Détecter l’appui sur “é” en javascript2013-11-17T00:40:00+01:002013-11-17T00:40:00+01:00Phykstag:localhost,2013-11-17:/Blog/output/2013/11/detecter-lappui-sur-e-en-javascript.html<p>Pour les besoins d’un plugin pour le thème
<a href="https://github.com/tmos/greeder">greeder</a> de
<a href="https://github.com/ldleman/Leed">Leed</a> (gestion des raccourcis
claviers), je devais détecter l’appui sur n’importe quelle touche du
clavier en javascript. Pour ce faire, a priori, ce n’est pas très dur,
il suffit de surveiller l’événement onkeydown et de …</p><p>Pour les besoins d’un plugin pour le thème
<a href="https://github.com/tmos/greeder">greeder</a> de
<a href="https://github.com/ldleman/Leed">Leed</a> (gestion des raccourcis
claviers), je devais détecter l’appui sur n’importe quelle touche du
clavier en javascript. Pour ce faire, a priori, ce n’est pas très dur,
il suffit de surveiller l’événement onkeydown et de récupérer le keycode
correspondant. Cette méthode fonctionne sans problèmes sur des claviers
azerty / qwerty (tout du moins pour ce que je voulais faire) mais pose
de graves problèmes sur des dispositions exotiques type Bépo (ty
<a href="http://tomcanac.com/blog/">tmos</a> de me l’avoir signalé :). En effet,
ces dispositions possèdent de nombreuses touches particulières, qui ne
sont pas traitées par la méthode précédente. Ainsi, il était impossible
d’assigner un raccourci à la touche “é” ou “É” par la méthode précédente
(pas de problème sur un clavier azerty/qwerty car cette touche est alors
détectée comme “2”).</p>
<p>Après quelques recherches, j’ai découvert qu’il existait déjà deux
moyens de savoir quelle touche était pressée : which et keycode. Dans la
majorité des cas, ils fournissent le même résultat, sauf dans le cas
qu’on veut justement traiter. Je n’ai pas approfondi la question mais il
semble que which est plus général, et d’après mes tests, il fonctionne
sur toutes les touches utiles d’un clavier azerty/qwerty/bépo. Attention
en revanche, les codes renvoyés par which peuvent différer des keycode
pour les caractères exotiques.</p>
<p>Mais cela ne suffisait pas. J’avais beau utiliser which qui devait me
retourner un certain code de touche, je n’avais rien. Après quelques
tests, je me suis alors aperçu qu’il n’y avait purement et simplement
aucun événement lancé lors de l’appui sur la touche fautive…</p>
<p>En effet, il existe encore une fois plusieurs événements disponibles sur
l’appui d’une touche. Le plus simple, et le plus naturellement adapté
pour détecter des raccourcis claviers est onkeydown, qui n’est émis
qu’une seule fois, lors de l’appui d’une touche. Mais cet événement
n’est pas déclenché lors de l’appui sur certains caractères spéciaux
(dont é). La solution est alors de faire un code légèrement plus lourd
en utilisant onkeypress en remplacement. onkeypress est déclenché tant
que la touche est appuyée (ce qui veut dire de potentiels événements
multiples, contrairement à onkeydown) mais a le mérite de fonctionner
avec toutes les touches des dispositions azerty/qwerty/bépo.</p>
<p>En résumé, pour détecter un appui sur n’importe quelle touche du
clavier, il faut utiliser l’événement onkeypress et détecter le code de
la touche avec which. Cela fonctionnera, en échange d’une légère baisse
de performances du script. Dommage que ceci n’ait pas été harmonisé ou
simplifié un minimum…</p>Premier article (parce qu’il en faut bien un :)2013-11-16T23:30:00+01:002013-11-16T23:30:00+01:00Phykstag:localhost,2013-11-16:/Blog/output/2013/11/premier-article-parce-quil-en-faut-bien-un.html<p>Ça y est, mon blog est enfin en ligne. Depuis le temps que j’ai cette
idée en tête (et que la page <a href="http://phyks.me">http://phyks.me</a> affiche un magnifique
“Blog coming soon”), j’ai enfin eu le temps de finaliser les deux /
trois trucs impératifs avant de le lancer. :)</p>
<p>J …</p><p>Ça y est, mon blog est enfin en ligne. Depuis le temps que j’ai cette
idée en tête (et que la page <a href="http://phyks.me">http://phyks.me</a> affiche un magnifique
“Blog coming soon”), j’ai enfin eu le temps de finaliser les deux /
trois trucs impératifs avant de le lancer. :)</p>
<p>J’ai donc enfin ma petite parcelle de web où partager diverses astuces
sur les trucs que j’utilise quotidiennement (et quelques coups de
gueules aussi). Entre autres, des petits trucs sur Arch Linux, sur de la
prog, sur l’autohébergement et des trucs en vrac. J’en ai également
profité pour mettre en place un
<a href="https://github.com/sebsauvage/Shaarli">shaarli</a> (que j’utilise en fait
déjà depuis quelques temps), <a href="http://links.phyks.me">ici</a>. Il y aura des
articles en français (principalement) et quelquefois en anglais quand
c’est un truc que je n’ai trouvé nulle part ailleurs.</p>
<p>Pour ceux qui se demanderaient comment fonctionne le blog en
arrière-plan, c’est un blog statique sur moteur fait-maison. J’avais eu
l’idée de faire un système de blog sur dépôt Git et avait commencé à le
coder, avant de me rendre compte que de nombreux projets existaient déjà
:/ Bref, ayant la flemme de reprendre un code existant en l’adaptant à
mes besoins et ayant déjà commencé à réinventer la roue, j’ai continué
mon bout de code, aboutissant à ce blog. Le code est d’ores et déjà
disponible sur <a href="https://github.com/phyks/blogit">Github</a>, mais il manque
encore quelques fonctions et cette instance sera l’occasion d’un test en
grandeur nature. Il sera mis à jour prochainement, quand j’aurai corrigé
tous les petits trucs qui ne me plaisent pas et refactorisé un peu le code.</p>
<p>Le blog est donc intégralement stocké sous forme de fichiers html dans
un dépôt Git (sur mon petit dédié chez <span class="caps">OVH</span>) et un hook lancé au commit
s’occupe de générer les fichiers html servis par le serveur web. Les
articles sont rédigés de façon très basique en html pour l’instant (mais
je prévois d’implémenter une syntaxe à la markdown dans un futur
proche), et tout est un peu fait “old school” (pas de formulaire tout
joli avec drag&drop pour envoyer des images par exemple, je suis plus
efficace sans). Ça peut paraître bancal parfois, mais ça me va bien :)
Du coup, pas de commentaires sur ce blog, ne voulant pas ajouter un
service externe à la Disqus. De toutes façons, je rejoins l’avis de
<a href="http://www.bortzmeyer.org/no-comment.html">Bortzmeyer</a> sur la question.
J’adore les commentaires constructifs, mais je préfère lire des articles
complets sur un blog qu’une réponse en deux lignes en bas d’un article.
Si vous voulez commenter, n’hésitez pas à m’envoyer un e-mail ou à me
dire si vous réagissez quelque part. :)</p>
<p><em><span class="caps">P.S.</span></em> : Merci à <a href="http://sebsauvage.net/">sebsauvage</a>, <a href="http://lehollandaisvolant.net/">le hollandais
volant</a>,
<a href="http://blog.idleman.fr">idleman</a>, <a href="http://ploum.net/">Ploum</a> et tous
les autres de la blogosphère française que j’oublie, que je suis depuis
quelques temps déjà, plus ou moins silencieusement et qui m’ont donné
envie d’avoir mon petit espace à moi aussi !</p>
<h2 class="center" id="bref-ya-plus-quà">Bref, ya plus qu’à ! :)</h2>
<p><img alt="Keep calm and use the force" src="http://localhost/Blog/output/images/2013/11/first_keep_calm_force.jpg">
(Image sous licence <span class="caps">CC</span> 3.0 <span class="caps">BY</span> <span class="caps">NC</span> <span class="caps">SA</span> <a href="http://koboot.deviantart.com/#/art/Keep-calm-and-use-The-Force-192034100?hf=1">source</a>)</p>
<p>Note : Je suis en train de tout remettre en place sur mon serveur, suite
à une réinstallaton. Mon Jabber, mon serveur Git etc. reviendront donc
bientôt, quand j’aurai 5 minutes pour m’en occuper :(</p>