Thicket data repository for the EEG
1{
2 "id": "https://mort.io/blog/past-present-future/",
3 "title": "Platforms, Packaging, Progress",
4 "link": "https://mort.io/blog/past-present-future/",
5 "updated": "2017-08-28T00:00:00",
6 "published": "2017-08-28T00:00:00",
7 "summary": "<p>I recently decided to refresh and update my <a href=\"https://github.com/mor1/ocal/\">ocal</a> package,<a href=\"https://mort.io/blog/past-present-future/#1\">1</a> primarily to\nport it to use the excellent <a href=\"https://github.com/pqwy/notty/\">notty</a> before adding support for indicating\nweek-of-year. At the same time, I took the opportunity to update the build\ninfrastructure now that the OCaml world has some shiny new packaging and build\ntools to go with <a href=\"https://github.com/ocaml/opam/\">OPAM</a>, namely <a href=\"https://github.com/dbuenzli/topkg/\"><code>topkg</code></a> and <a href=\"https://github.com/janestreet/jbuilder/\"><code>jbuilder</code></a>. So, starting\nfrom <a href=\"http://github.com/djs55/\">Dave Scott’s</a> <a href=\"https://mirage.io/wiki/packaging\">wiki entry</a> about how to package <a href=\"https://mirage.io/\">Mirage</a> libraries,\nhere’s what I had to do…</p>\n<div>1\n<p>A somewhat over-featured replacement for the standard UNIX <code>cal</code> utility,\nbecause I got irritated by its American-centricity and my\ninitial <a href=\"https://github.com/mor1/python-scripts/blob/master/cal.py\">Python replacement</a> was just too slow…</p>\n</div>\n<h2><a href=\"https://mort.io/blog/past-present-future/#remove-oasis-remnants\">Remove Oasis remnants</a></h2>\n<pre><code><span><span><span>git</span></span><span> rm _oasis setup.ml Makefile<span>*</span> _tags myocamlbuild.ml .merlin</span>\n</span><span><span><span>mv</span></span><span> ocal.opam/opam o</span> <span>&&</span> <span><span>git</span></span><span> rm<span><span> -</span>rf</span> ocal.opam</span> <span>&&</span> <span><span>mv</span></span><span> o ocal.opam</span> <span>&&</span> <span><span>git</span></span><span> add ocal.opam</span>\n</span><span><span><span>cat</span></span><span> <span>></span></span><span>|</span> <span><span>.gitignore</span></span><span> <span><span><<</span><span>_EOF</span></span><span>\n</span></span></span><span><span><span>_build\n</span></span></span><span><span><span>*.merlin\n</span></span></span><span><span><span>*.install\n</span></span></span><span><span><span><span>_EOF</span></span></span>\n</span></code></pre>\n<p>Although we’re removing the <code>ocal.opam/descr</code> file, we’re not going to lose the\ncontent: we’re going to let <code>topkg opam pkg</code> use its default <code>--readme</code> option\nto extract the relevant info from the first marked up section of the\n<a href=\"https://github.com/mor1/ocal/blob/0.2.0/README.md\"><code>README.md</code></a>:</p>\n<pre><code><span><span><span><span>#</span> </span><span><span>ocal — An improved Unix <span><span>`</span>cal<span>`</span></span> utility</span><span>\n</span></span></span></span><span>\n</span><span><span>%%VERSION%%\n</span></span><span><span>\n</span></span><span><span>A replacement for the standard Unix <span><span>`</span>cal<span>`</span></span> utility. Partly because I could,\n</span></span><span><span>partly because I'd become too irritated with its command line interface.\n</span></span></code></pre>\n<p>We also remove but don’t lose the functionality of the <code>.merlin</code> and OPAM\n<code>ocal.install</code> files, as <a href=\"https://github.com/janestreet/jbuilder/\">jbuilder</a> will generate them for us.</p>\n<h2><a href=\"https://mort.io/blog/past-present-future/#create-src-jbuild-file\">Create <code>src/jbuild</code> file</a></h2>\n<pre><code><span><span><span>cat</span></span><span> <span>></span></span><span>|</span> <span><span>src/jbuild</span></span><span> <span><span><<</span><span>_EOF</span></span><span>\n</span></span></span><span><span><span>(jbuild_version 1)\n</span></span></span><span><span><span>\n</span></span></span><span><span><span>(executable\n</span></span></span><span><span><span> ((public_name ocal)\n</span></span></span><span><span><span> (package ocal)\n</span></span></span><span><span><span> (name main)\n</span></span></span><span><span><span>\n</span></span></span><span><span><span> (libraries\n</span></span></span><span><span><span> (\n</span></span></span><span><span><span> astring\n</span></span></span><span><span><span> calendar\n</span></span></span><span><span><span> cmdliner\n</span></span></span><span><span><span> notty\n</span></span></span><span><span><span> notty.unix\n</span></span></span><span><span><span> ))\n</span></span></span><span><span><span> (flags (:standard -w "A-44-48-52" -safe-string))\n</span></span></span><span><span><span> ))\n</span></span></span><span><span><span><span>_EOF</span></span></span>\n</span></code></pre>\n<p>This corresponds to the <a href=\"https://github.com/mor1/ocal/releases/tag/0.2.0\">0.2.0</a>\nrelease of <a href=\"https://github.com/mor1/ocal/\">ocal</a>. Note that the <code>name</code> parameter refers to the module that\ncontains the entrypoint for the executable, and that we turn on all warnings\n(<code>A</code>) except for three that we wish to ignore:</p>\n<ul>\n<li><code>44</code>: Open statement shadows an already defined identifier.</li>\n<li><code>48</code>: Implicit elimination of optional arguments.</li>\n<li><code>52</code>: (see 8.5.1) Fragile constant pattern.</li>\n</ul>\n<p>After I did some tidying up of the code to deal with the newly imposed warnings,\n<code>make</code> and <code>make install</code> satisfactorily (and quickly!) used <a href=\"https://github.com/janestreet/jbuilder/\">jbuilder</a> to\nbuild and install the executable as <code>~/.opam/system/bin/ocal</code> (thanks to the\n<code>public_name</code> stanza in the <code>src/jbuild</code> file, above). <code>make uninstall</code> then\ncaused <a href=\"https://github.com/janestreet/jbuilder/\">jbuilder</a> to remove it, before I <code>opam</code> pinned it and then reinstall\nthrough <code>opam</code> to check that workflow worked as well:</p>\n<pre><code><span><span><span>opam</span></span><span> remove ocal</span>\n</span><span><span><span>opam</span></span><span> pin add<span><span> -</span>yn</span><span><span> --</span>dev-repo</span> ocal .</span>\n</span><span><span><span>opam</span></span><span> install ocal</span>\n</span></code></pre>\n<h2><a href=\"https://mort.io/blog/past-present-future/#create-the-topkg-skeletons\">Create the <code>topkg</code> skeletons</a></h2>\n<p>Having refreshed the basic build infrastructure, next it’s time to update the\npackaging workflow. For a simple library we could use the automatic\n<a href=\"https://github.com/janestreet/jbuilder/\">jbuilder</a>/<a href=\"https://github.com/dbuenzli/topkg/\">topkg</a> plugin per the <a href=\"https://mirage.io/wiki/packaging\">wiki entry</a>:</p>\n<pre><code><span><span><span>mkdir</span></span><span> pkg</span>\n</span><span><span><span>cat</span></span><span> <span>></span></span><span>|</span> <span><span>pkg/pkg.ml</span></span><span> <span><span><<</span><span>_EOF</span></span><span>\n</span></span></span><span><span><span>#!/usr/bin/env ocaml\n</span></span></span><span><span><span>#use "topfind"\n</span></span></span><span><span><span>#require "topkg-jbuilder.auto"\n</span></span></span><span><span><span><span>_EOF</span></span></span>\n</span></code></pre>\n<p>However, this isn’t a library so we don’t have documentation to build so we\ndon’t bother with the <code>odoc</code> skeleton. As a result we also need to customise\n<a href=\"https://github.com/mor1/ocal/blob/0.2.0/pkg/pkg.ml\"><code>pkg/pkg.ml</code></a> so as to stop <code>topkg publish</code> failing when it can’t build docs:</p>\n<pre><code><span><span>#</span><span>!</span><span>/</span>usr<span>/</span>bin<span>/</span>env ocaml\n</span><span><span>#use</span> <span><span>"</span>topfind<span>"</span></span>\n</span><span><span>#require</span> <span><span>"</span>topkg-jbuilder<span>"</span></span>\n</span><span>\n</span><span><span><span>open</span> <span>Topkg</span>\n</span></span><span>\n</span><span><span>let</span> <span>publish</span> <span>=</span>\n</span><span> <span>Pkg.</span>publish <span>~artefacts<span>:</span></span><span><span>[</span><span>`Distrib</span><span>]</span></span> <span>(<span>)</span></span>\n</span><span>\n</span><span><span>let</span> <span>(<span>)</span></span> <span>=</span>\n</span><span> <span>Topkg_jbuilder.</span>describe <span>~publish</span> <span>(<span>)</span></span>\n</span></code></pre>\n<h2><a href=\"https://mort.io/blog/past-present-future/#prepare-a-release\">Prepare a release</a></h2>\n<p>Finally, we follow the standard <a href=\"https://github.com/dbuenzli/topkg/\">topkg</a> workflow to prepare a release. First,\nadd an entry to <a href=\"https://github.com/mor1/ocal/blob/0.2.0/CHANGES.md\"><code>CHANGES.md</code></a> with the correct formatting and commit the\nresult, and then:</p>\n<pre><code><span><span><span>distrib</span></span><span>:</span>\n<span></span><span></span></span><span><span></span><span>\t<span><span>[</span><span> <span><span>-</span>x</span> <span><span>$$(</span>opam config var root<span>)</span></span>/plugins/opam-publish/repos/ocal <span>]</span></span> <span>||</span> <span>\\\n</span></span></span></span><span><span><span>\t <span><span>opam-publish</span></span><span> repo add ocal mor1/ocal</span></span>\n</span></span><span><span>\t<span><span><span>topkg</span></span><span> tag</span></span>\n</span></span><span><span>\t<span><span><span>topkg</span></span><span> distrib</span></span>\n</span></span></code></pre>\n<p>…which creates tokens for accessing the GitHub repo for this project (if they\ndon’t already exist), creates a release tag based on entries in <a href=\"https://github.com/mor1/ocal/blob/0.2.0/CHANGES.md\"><code>CHANGES.md</code></a>,\nand then creates the release tarballs (without the edits to <a href=\"https://github.com/mor1/ocal/blob/0.2.0/pkg/pkg.ml\"><code>pkg/pkg.ml</code></a> this\nwould also build the docs, but we have none).</p>\n<h2><a href=\"https://mort.io/blog/past-present-future/#publish-a-release\">Publish a release</a></h2>\n<p>Finally, we publish the release to GitHub and issue a pull request to\nthe <a href=\"https://github.com/ocaml/opam/\">OPAM repository</a> to add the new release into OPAM after linting and\ntests have passed.</p>\n<pre><code><span><span><span>publish</span></span><span>:</span>\n<span></span><span></span></span><span><span></span><span>\t<span><span><span>topkg</span></span><span> publish</span></span>\n</span></span><span><span>\t<span><span><span>topkg</span></span><span> opam pkg</span></span>\n</span></span><span><span>\t<span><span><span>topkg</span></span><span> opam submit</span></span>\n</span></span></code></pre>\n<p>Given that this repo has only a single package, we could in fact simply issue</p>\n<pre><code><span>topkg tag && topkg bistro\n</span></code></pre>\n<p>Also, as an alternative to customising the <a href=\"https://github.com/mor1/ocal/blob/0.2.0/pkg/pkg.ml\"><code>pkg/pkg.ml</code></a> as indicated above, we\ncould simply remember to indicate the appropriate customisation on the command\nline:</p>\n<pre><code><span>topkg publish distrib\n</span></code></pre>\n<p>…but <code>topkg bistro</code> wouldn’t then work.</p>\n<h2><a href=\"https://mort.io/blog/past-present-future/#conclusion\">Conclusion</a></h2>\n<p>So that’s it: a simple executable distribution taken from old-school <a href=\"http://oasis.forge.ocamlcore.org/\">Oasis</a> and\n<a href=\"https://ocaml.org/learn/tutorials/ocamlbuild/\">OCamlBuild</a> infrastructure to shiny new modern <a href=\"https://github.com/janestreet/jbuilder/\">jbuilder</a> and <a href=\"https://github.com/dbuenzli/topkg/\">topkg</a>. The new\nscheme seems to me to be an improvement: faster build times, simpler (to my\neyes) metadata, autogeneration of more of the repeated metadata (<code>.merlin</code> etc),\nand a reasonably simple <a href=\"https://github.com/mor1/ocal/blob/0.2.0/Makefile\"><code>Makefile</code></a> that I actually think I understand.\nDefinitely progress :)</p>",
8 "content": "<p>I recently decided to refresh and update my <a href=\"https://github.com/mor1/ocal/\">ocal</a> package,<a href=\"https://mort.io/blog/past-present-future/#1\">1</a> primarily to\nport it to use the excellent <a href=\"https://github.com/pqwy/notty/\">notty</a> before adding support for indicating\nweek-of-year. At the same time, I took the opportunity to update the build\ninfrastructure now that the OCaml world has some shiny new packaging and build\ntools to go with <a href=\"https://github.com/ocaml/opam/\">OPAM</a>, namely <a href=\"https://github.com/dbuenzli/topkg/\"><code>topkg</code></a> and <a href=\"https://github.com/janestreet/jbuilder/\"><code>jbuilder</code></a>. So, starting\nfrom <a href=\"http://github.com/djs55/\">Dave Scott’s</a> <a href=\"https://mirage.io/wiki/packaging\">wiki entry</a> about how to package <a href=\"https://mirage.io/\">Mirage</a> libraries,\nhere’s what I had to do…</p>\n<div>1\n<p>A somewhat over-featured replacement for the standard UNIX <code>cal</code> utility,\nbecause I got irritated by its American-centricity and my\ninitial <a href=\"https://github.com/mor1/python-scripts/blob/master/cal.py\">Python replacement</a> was just too slow…</p>\n</div>\n<h2><a href=\"https://mort.io/blog/past-present-future/#remove-oasis-remnants\">Remove Oasis remnants</a></h2>\n<pre><code><span><span><span>git</span></span><span> rm _oasis setup.ml Makefile<span>*</span> _tags myocamlbuild.ml .merlin</span>\n</span><span><span><span>mv</span></span><span> ocal.opam/opam o</span> <span>&&</span> <span><span>git</span></span><span> rm<span><span> -</span>rf</span> ocal.opam</span> <span>&&</span> <span><span>mv</span></span><span> o ocal.opam</span> <span>&&</span> <span><span>git</span></span><span> add ocal.opam</span>\n</span><span><span><span>cat</span></span><span> <span>></span></span><span>|</span> <span><span>.gitignore</span></span><span> <span><span><<</span><span>_EOF</span></span><span>\n</span></span></span><span><span><span>_build\n</span></span></span><span><span><span>*.merlin\n</span></span></span><span><span><span>*.install\n</span></span></span><span><span><span><span>_EOF</span></span></span>\n</span></code></pre>\n<p>Although we’re removing the <code>ocal.opam/descr</code> file, we’re not going to lose the\ncontent: we’re going to let <code>topkg opam pkg</code> use its default <code>--readme</code> option\nto extract the relevant info from the first marked up section of the\n<a href=\"https://github.com/mor1/ocal/blob/0.2.0/README.md\"><code>README.md</code></a>:</p>\n<pre><code><span><span><span><span>#</span> </span><span><span>ocal — An improved Unix <span><span>`</span>cal<span>`</span></span> utility</span><span>\n</span></span></span></span><span>\n</span><span><span>%%VERSION%%\n</span></span><span><span>\n</span></span><span><span>A replacement for the standard Unix <span><span>`</span>cal<span>`</span></span> utility. Partly because I could,\n</span></span><span><span>partly because I'd become too irritated with its command line interface.\n</span></span></code></pre>\n<p>We also remove but don’t lose the functionality of the <code>.merlin</code> and OPAM\n<code>ocal.install</code> files, as <a href=\"https://github.com/janestreet/jbuilder/\">jbuilder</a> will generate them for us.</p>\n<h2><a href=\"https://mort.io/blog/past-present-future/#create-src-jbuild-file\">Create <code>src/jbuild</code> file</a></h2>\n<pre><code><span><span><span>cat</span></span><span> <span>></span></span><span>|</span> <span><span>src/jbuild</span></span><span> <span><span><<</span><span>_EOF</span></span><span>\n</span></span></span><span><span><span>(jbuild_version 1)\n</span></span></span><span><span><span>\n</span></span></span><span><span><span>(executable\n</span></span></span><span><span><span> ((public_name ocal)\n</span></span></span><span><span><span> (package ocal)\n</span></span></span><span><span><span> (name main)\n</span></span></span><span><span><span>\n</span></span></span><span><span><span> (libraries\n</span></span></span><span><span><span> (\n</span></span></span><span><span><span> astring\n</span></span></span><span><span><span> calendar\n</span></span></span><span><span><span> cmdliner\n</span></span></span><span><span><span> notty\n</span></span></span><span><span><span> notty.unix\n</span></span></span><span><span><span> ))\n</span></span></span><span><span><span> (flags (:standard -w "A-44-48-52" -safe-string))\n</span></span></span><span><span><span> ))\n</span></span></span><span><span><span><span>_EOF</span></span></span>\n</span></code></pre>\n<p>This corresponds to the <a href=\"https://github.com/mor1/ocal/releases/tag/0.2.0\">0.2.0</a>\nrelease of <a href=\"https://github.com/mor1/ocal/\">ocal</a>. Note that the <code>name</code> parameter refers to the module that\ncontains the entrypoint for the executable, and that we turn on all warnings\n(<code>A</code>) except for three that we wish to ignore:</p>\n<ul>\n<li><code>44</code>: Open statement shadows an already defined identifier.</li>\n<li><code>48</code>: Implicit elimination of optional arguments.</li>\n<li><code>52</code>: (see 8.5.1) Fragile constant pattern.</li>\n</ul>\n<p>After I did some tidying up of the code to deal with the newly imposed warnings,\n<code>make</code> and <code>make install</code> satisfactorily (and quickly!) used <a href=\"https://github.com/janestreet/jbuilder/\">jbuilder</a> to\nbuild and install the executable as <code>~/.opam/system/bin/ocal</code> (thanks to the\n<code>public_name</code> stanza in the <code>src/jbuild</code> file, above). <code>make uninstall</code> then\ncaused <a href=\"https://github.com/janestreet/jbuilder/\">jbuilder</a> to remove it, before I <code>opam</code> pinned it and then reinstall\nthrough <code>opam</code> to check that workflow worked as well:</p>\n<pre><code><span><span><span>opam</span></span><span> remove ocal</span>\n</span><span><span><span>opam</span></span><span> pin add<span><span> -</span>yn</span><span><span> --</span>dev-repo</span> ocal .</span>\n</span><span><span><span>opam</span></span><span> install ocal</span>\n</span></code></pre>\n<h2><a href=\"https://mort.io/blog/past-present-future/#create-the-topkg-skeletons\">Create the <code>topkg</code> skeletons</a></h2>\n<p>Having refreshed the basic build infrastructure, next it’s time to update the\npackaging workflow. For a simple library we could use the automatic\n<a href=\"https://github.com/janestreet/jbuilder/\">jbuilder</a>/<a href=\"https://github.com/dbuenzli/topkg/\">topkg</a> plugin per the <a href=\"https://mirage.io/wiki/packaging\">wiki entry</a>:</p>\n<pre><code><span><span><span>mkdir</span></span><span> pkg</span>\n</span><span><span><span>cat</span></span><span> <span>></span></span><span>|</span> <span><span>pkg/pkg.ml</span></span><span> <span><span><<</span><span>_EOF</span></span><span>\n</span></span></span><span><span><span>#!/usr/bin/env ocaml\n</span></span></span><span><span><span>#use "topfind"\n</span></span></span><span><span><span>#require "topkg-jbuilder.auto"\n</span></span></span><span><span><span><span>_EOF</span></span></span>\n</span></code></pre>\n<p>However, this isn’t a library so we don’t have documentation to build so we\ndon’t bother with the <code>odoc</code> skeleton. As a result we also need to customise\n<a href=\"https://github.com/mor1/ocal/blob/0.2.0/pkg/pkg.ml\"><code>pkg/pkg.ml</code></a> so as to stop <code>topkg publish</code> failing when it can’t build docs:</p>\n<pre><code><span><span>#</span><span>!</span><span>/</span>usr<span>/</span>bin<span>/</span>env ocaml\n</span><span><span>#use</span> <span><span>"</span>topfind<span>"</span></span>\n</span><span><span>#require</span> <span><span>"</span>topkg-jbuilder<span>"</span></span>\n</span><span>\n</span><span><span><span>open</span> <span>Topkg</span>\n</span></span><span>\n</span><span><span>let</span> <span>publish</span> <span>=</span>\n</span><span> <span>Pkg.</span>publish <span>~artefacts<span>:</span></span><span><span>[</span><span>`Distrib</span><span>]</span></span> <span>(<span>)</span></span>\n</span><span>\n</span><span><span>let</span> <span>(<span>)</span></span> <span>=</span>\n</span><span> <span>Topkg_jbuilder.</span>describe <span>~publish</span> <span>(<span>)</span></span>\n</span></code></pre>\n<h2><a href=\"https://mort.io/blog/past-present-future/#prepare-a-release\">Prepare a release</a></h2>\n<p>Finally, we follow the standard <a href=\"https://github.com/dbuenzli/topkg/\">topkg</a> workflow to prepare a release. First,\nadd an entry to <a href=\"https://github.com/mor1/ocal/blob/0.2.0/CHANGES.md\"><code>CHANGES.md</code></a> with the correct formatting and commit the\nresult, and then:</p>\n<pre><code><span><span><span>distrib</span></span><span>:</span>\n<span></span><span></span></span><span><span></span><span>\t<span><span>[</span><span> <span><span>-</span>x</span> <span><span>$$(</span>opam config var root<span>)</span></span>/plugins/opam-publish/repos/ocal <span>]</span></span> <span>||</span> <span>\\\n</span></span></span></span><span><span><span>\t <span><span>opam-publish</span></span><span> repo add ocal mor1/ocal</span></span>\n</span></span><span><span>\t<span><span><span>topkg</span></span><span> tag</span></span>\n</span></span><span><span>\t<span><span><span>topkg</span></span><span> distrib</span></span>\n</span></span></code></pre>\n<p>…which creates tokens for accessing the GitHub repo for this project (if they\ndon’t already exist), creates a release tag based on entries in <a href=\"https://github.com/mor1/ocal/blob/0.2.0/CHANGES.md\"><code>CHANGES.md</code></a>,\nand then creates the release tarballs (without the edits to <a href=\"https://github.com/mor1/ocal/blob/0.2.0/pkg/pkg.ml\"><code>pkg/pkg.ml</code></a> this\nwould also build the docs, but we have none).</p>\n<h2><a href=\"https://mort.io/blog/past-present-future/#publish-a-release\">Publish a release</a></h2>\n<p>Finally, we publish the release to GitHub and issue a pull request to\nthe <a href=\"https://github.com/ocaml/opam/\">OPAM repository</a> to add the new release into OPAM after linting and\ntests have passed.</p>\n<pre><code><span><span><span>publish</span></span><span>:</span>\n<span></span><span></span></span><span><span></span><span>\t<span><span><span>topkg</span></span><span> publish</span></span>\n</span></span><span><span>\t<span><span><span>topkg</span></span><span> opam pkg</span></span>\n</span></span><span><span>\t<span><span><span>topkg</span></span><span> opam submit</span></span>\n</span></span></code></pre>\n<p>Given that this repo has only a single package, we could in fact simply issue</p>\n<pre><code><span>topkg tag && topkg bistro\n</span></code></pre>\n<p>Also, as an alternative to customising the <a href=\"https://github.com/mor1/ocal/blob/0.2.0/pkg/pkg.ml\"><code>pkg/pkg.ml</code></a> as indicated above, we\ncould simply remember to indicate the appropriate customisation on the command\nline:</p>\n<pre><code><span>topkg publish distrib\n</span></code></pre>\n<p>…but <code>topkg bistro</code> wouldn’t then work.</p>\n<h2><a href=\"https://mort.io/blog/past-present-future/#conclusion\">Conclusion</a></h2>\n<p>So that’s it: a simple executable distribution taken from old-school <a href=\"http://oasis.forge.ocamlcore.org/\">Oasis</a> and\n<a href=\"https://ocaml.org/learn/tutorials/ocamlbuild/\">OCamlBuild</a> infrastructure to shiny new modern <a href=\"https://github.com/janestreet/jbuilder/\">jbuilder</a> and <a href=\"https://github.com/dbuenzli/topkg/\">topkg</a>. The new\nscheme seems to me to be an improvement: faster build times, simpler (to my\neyes) metadata, autogeneration of more of the repeated metadata (<code>.merlin</code> etc),\nand a reasonably simple <a href=\"https://github.com/mor1/ocal/blob/0.2.0/Makefile\"><code>Makefile</code></a> that I actually think I understand.\nDefinitely progress :)</p>",
9 "content_type": "html",
10 "author": {
11 "name": "Unknown",
12 "email": null,
13 "uri": null
14 },
15 "categories": [],
16 "source": "https://mort.io/atom.xml"
17}