Thicket data repository for the EEG
at main 152 kB view raw
1{ 2 "id": "https://ryan.freumh.org/how-this-site-is-built.html", 3 "title": "How This Site Is Build", 4 "link": "https://ryan.freumh.org/how-this-site-is-built.html", 5 "updated": "2025-07-16T00:00:00", 6 "published": "2025-03-26T00:00:00", 7 "summary": "<div>\n \n <span>Published 26 Mar 2025.</span>\n \n \n <span>Last update 16 Jul 2025.</span>\n \n </div>\n \n \n\n <p><span>This site has continuously evolved since I made the\nfirst commit while procrastinating my undergrad dissertation,</span></p>\n<div><pre><code><span><a href=\"#cb1-1\"></a>commit 632cb1f0c97c07fb99b48192444397e56ea5310f</span>\n<span><a href=\"#cb1-2\"></a>Author: Ryan Gibb &lt;redacted&gt;</span>\n<span><a href=\"#cb1-3\"></a>Date: Fri Jan 22 11:27:55 2021 +0000</span>\n<span><a href=\"#cb1-4\"></a></span>\n<span><a href=\"#cb1-5\"></a> Initial commit</span>\n<span><a href=\"#cb1-6\"></a></span>\n<span><a href=\"#cb1-7\"></a><span>diff --git a/index.html b/index.html</span></span>\n<span><a href=\"#cb1-8\"></a>new file mode 100644</span>\n<span><a href=\"#cb1-9\"></a>index 0000000..557db03</span>\n<span><a href=\"#cb1-10\"></a><span>--- /dev/null</span></span>\n<span><a href=\"#cb1-11\"></a><span>+++ b/index.html</span></span>\n<span><a href=\"#cb1-12\"></a><span>@@ -0,0 +1 @@</span></span>\n<span><a href=\"#cb1-13\"></a><span>+Hello World</span></span></code></pre></div>\n<p><span>I started off writing plain HTML, then switching to\nwriting in markdown and using <a href=\"https://pandoc.org/\">pandoc</a>\nto convert to HTML, and gradually accumulated bash scripts and makefiles\nto add more functionality, such as generating an <a href=\"https://www.rfc-editor.org/rfc/rfc4287\">Atom feed</a>. This became\nunmaintainable and at the start of 2025 I overhauled it to use the <a href=\"https://jaspervdj.be/hakyll/\">Hakyll</a> static site generator\nThere’s a few drafts in the git repository which I don’t want to make\npublic yet, so I include the source code used to generate this website\nbelow. It’s quite particular to my needs – Hakyll give you a big bag of\ntools which you can compose in your own way – but it may be useful as a\nreference.</span></p>\n<div><pre><code><span><a href=\"#cb2-1\"></a><span>{-# LANGUAGE OverloadedStrings #-}</span></span>\n<span><a href=\"#cb2-2\"></a><span>{-# LANGUAGE ScopedTypeVariables #-}</span></span>\n<span><a href=\"#cb2-3\"></a></span>\n<span><a href=\"#cb2-4\"></a><span>import</span> <span>Bib</span></span>\n<span><a href=\"#cb2-5\"></a><span>import</span> <span>BibHakyll</span></span>\n<span><a href=\"#cb2-6\"></a></span>\n<span><a href=\"#cb2-7\"></a><span>import</span> <span>Control.Applicative</span> ((&lt;|&gt;))</span>\n<span><a href=\"#cb2-8\"></a><span>import</span> <span>Control.Monad</span> (filterM, forM, liftM, (&gt;=&gt;), forM_)</span>\n<span><a href=\"#cb2-9\"></a><span>import</span> <span>Control.Monad.IO.Class</span> (liftIO)</span>\n<span><a href=\"#cb2-10\"></a><span>import</span> <span>Data.Aeson</span></span>\n<span><a href=\"#cb2-11\"></a><span>import</span> <span>Data.Aeson.Types</span> (<span>Parser</span>)</span>\n<span><a href=\"#cb2-12\"></a><span>import</span> <span>qualified</span> <span>Data.ByteString.Lazy</span> <span>as</span> <span>BSL</span></span>\n<span><a href=\"#cb2-13\"></a><span>import</span> <span>Data.Char</span> (isAlphaNum)</span>\n<span><a href=\"#cb2-14\"></a><span>import</span> <span>qualified</span> <span>Data.Char</span> <span>as</span> <span>C</span></span>\n<span><a href=\"#cb2-15\"></a><span>import</span> <span>Data.Either</span> (fromRight)</span>\n<span><a href=\"#cb2-16\"></a><span>import</span> <span>qualified</span> <span>Data.HashMap.Strict</span> <span>as</span> <span>HM</span></span>\n<span><a href=\"#cb2-17\"></a><span>import</span> <span>qualified</span> <span>Data.List</span> <span>as</span> <span>L</span></span>\n<span><a href=\"#cb2-18\"></a><span>import</span> <span>qualified</span> <span>Data.Map</span> <span>as</span> <span>M</span></span>\n<span><a href=\"#cb2-19\"></a><span>import</span> <span>Data.Maybe</span> (catMaybes, fromMaybe, isJust, listToMaybe, mapMaybe)</span>\n<span><a href=\"#cb2-20\"></a><span>import</span> <span>Data.Monoid</span> (mappend)</span>\n<span><a href=\"#cb2-21\"></a><span>import</span> <span>Data.Text</span> (<span>Text</span>, intercalate, isInfixOf, pack, unpack)</span>\n<span><a href=\"#cb2-22\"></a><span>import</span> <span>qualified</span> <span>Data.Text</span> <span>as</span> <span>T</span></span>\n<span><a href=\"#cb2-23\"></a><span>import</span> <span>Data.Time</span> (<span>UTCTime</span> (<span>UTCTime</span>))</span>\n<span><a href=\"#cb2-24\"></a><span>import</span> <span>Data.Time.Format</span> (formatTime, parseTimeM)</span>\n<span><a href=\"#cb2-25\"></a><span>import</span> <span>Data.Time.Locale.Compat</span> (defaultTimeLocale)</span>\n<span><a href=\"#cb2-26\"></a><span>import</span> <span>Graphics.HsExif</span></span>\n<span><a href=\"#cb2-27\"></a><span>import</span> <span>Hakyll</span></span>\n<span><a href=\"#cb2-28\"></a><span>import</span> <span>Numeric</span> (showFFloat)</span>\n<span><a href=\"#cb2-29\"></a><span>import</span> <span>System.Directory</span> (doesFileExist)</span>\n<span><a href=\"#cb2-30\"></a><span>import</span> <span>System.FilePath</span> (takeBaseName, takeFileName)</span>\n<span><a href=\"#cb2-31\"></a><span>import</span> <span>Text.Blaze.Html</span> (toHtml, toValue, (!))</span>\n<span><a href=\"#cb2-32\"></a><span>import</span> <span>qualified</span> <span>Text.Blaze.Html</span> <span>as</span> <span>ExifTag</span></span>\n<span><a href=\"#cb2-33\"></a><span>import</span> <span>Text.Blaze.Html.Renderer.String</span> (renderHtml)</span>\n<span><a href=\"#cb2-34\"></a><span>import</span> <span>qualified</span> <span>Text.Blaze.Html5</span> <span>as</span> <span>H</span></span>\n<span><a href=\"#cb2-35\"></a><span>import</span> <span>qualified</span> <span>Text.Blaze.Html5.Attributes</span> <span>as</span> <span>A</span></span>\n<span><a href=\"#cb2-36\"></a><span>import</span> <span>Text.Pandoc</span></span>\n<span><a href=\"#cb2-37\"></a><span>import</span> <span>Text.Pandoc.Highlighting</span> (pygments)</span>\n<span><a href=\"#cb2-38\"></a><span>import</span> <span>Text.Pandoc.Lua</span> (applyFilter)</span>\n<span><a href=\"#cb2-39\"></a><span>import</span> <span>Data.Ord</span> (comparing)</span>\n<span><a href=\"#cb2-40\"></a><span>import</span> <span>Data.Time</span> (<span>UTCTime</span>(<span>UTCTime</span>), parseTimeOrError, defaultTimeLocale) <span>--, parseTimeM, parseTime)</span></span>\n<span><a href=\"#cb2-41\"></a></span>\n<span><a href=\"#cb2-42\"></a>indexFiles <span>=</span></span>\n<span><a href=\"#cb2-43\"></a> <span>&quot;static/home.org&quot;</span></span>\n<span><a href=\"#cb2-44\"></a> <span>.||.</span> <span>&quot;static/logs.org&quot;</span></span>\n<span><a href=\"#cb2-45\"></a> <span>.||.</span> <span>&quot;static/news.org&quot;</span></span>\n<span><a href=\"#cb2-46\"></a> <span>.||.</span> <span>&quot;static/index.org&quot;</span></span>\n<span><a href=\"#cb2-47\"></a> <span>.||.</span> <span>&quot;static/photos.org&quot;</span></span>\n<span><a href=\"#cb2-48\"></a> <span>.||.</span> <span>&quot;static/papers.org&quot;</span></span>\n<span><a href=\"#cb2-49\"></a></span>\n<span><a href=\"#cb2-50\"></a>tagFiles <span>=</span></span>\n<span><a href=\"#cb2-51\"></a> <span>&quot;static/projects.org&quot;</span></span>\n<span><a href=\"#cb2-52\"></a> <span>.||.</span> <span>&quot;static/research.org&quot;</span></span>\n<span><a href=\"#cb2-53\"></a> <span>.||.</span> <span>&quot;static/technology.org&quot;</span></span>\n<span><a href=\"#cb2-54\"></a> <span>.||.</span> <span>&quot;static/self-hosting.org&quot;</span></span>\n<span><a href=\"#cb2-55\"></a></span>\n<span><a href=\"#cb2-56\"></a>htmlFiles <span>=</span> <span>&quot;static/**.md&quot;</span> <span>.||.</span> <span>&quot;static/**.org&quot;</span></span>\n<span><a href=\"#cb2-57\"></a></span>\n<span><a href=\"#cb2-58\"></a>postFiles <span>=</span> htmlFiles <span>.&amp;&amp;.</span> complement indexFiles <span>.&amp;&amp;.</span> complement tagFiles</span>\n<span><a href=\"#cb2-59\"></a></span>\n<span><a href=\"#cb2-60\"></a>photoFiles <span>=</span> <span>&quot;static/photos/*&quot;</span></span>\n<span><a href=\"#cb2-61\"></a></span>\n<span><a href=\"#cb2-62\"></a>logFiles <span>=</span> fromRegex <span>&quot;static/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].*&quot;</span></span>\n<span><a href=\"#cb2-63\"></a></span>\n<span><a href=\"#cb2-64\"></a>articleFiles <span>=</span> postFiles <span>.&amp;&amp;.</span> complement logFiles</span>\n<span><a href=\"#cb2-65\"></a></span>\n<span><a href=\"#cb2-66\"></a><span>dateFormat ::</span> <span>String</span></span>\n<span><a href=\"#cb2-67\"></a>dateFormat <span>=</span> <span>&quot;%e %b %Y&quot;</span></span>\n<span><a href=\"#cb2-68\"></a></span>\n<span><a href=\"#cb2-69\"></a><span>feedConfiguration ::</span> <span>FeedConfiguration</span></span>\n<span><a href=\"#cb2-70\"></a>feedConfiguration <span>=</span></span>\n<span><a href=\"#cb2-71\"></a> <span>FeedConfiguration</span></span>\n<span><a href=\"#cb2-72\"></a> { feedTitle <span>=</span> <span>&quot;ryan.freumh.org&quot;</span>,</span>\n<span><a href=\"#cb2-73\"></a> feedDescription <span>=</span> <span>&quot;ryan.freumh.org&quot;</span>,</span>\n<span><a href=\"#cb2-74\"></a> feedAuthorName <span>=</span> <span>&quot;Ryan Gibb&quot;</span>,</span>\n<span><a href=\"#cb2-75\"></a> feedAuthorEmail <span>=</span> <span>&quot;ryan@freumh.org&quot;</span>,</span>\n<span><a href=\"#cb2-76\"></a> feedRoot <span>=</span> <span>&quot;https://ryan.freumh.org&quot;</span></span>\n<span><a href=\"#cb2-77\"></a> }</span>\n<span><a href=\"#cb2-78\"></a></span>\n<span><a href=\"#cb2-79\"></a><span>main ::</span> <span>IO</span> ()</span>\n<span><a href=\"#cb2-80\"></a>main <span>=</span> hakyll <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-81\"></a> tags <span>&lt;-</span> buildTags postFiles (fromCapture <span>&quot;*.html&quot;</span>)</span>\n<span><a href=\"#cb2-82\"></a></span>\n<span><a href=\"#cb2-83\"></a> match tagFiles <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-84\"></a> route idRoute</span>\n<span><a href=\"#cb2-85\"></a> compile tagCompiler</span>\n<span><a href=\"#cb2-86\"></a></span>\n<span><a href=\"#cb2-87\"></a> tagsRules tags <span>$</span> \\tag <span>pattern</span> <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-88\"></a> route idRoute</span>\n<span><a href=\"#cb2-89\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-90\"></a> <span>let</span> title <span>=</span> titleCase tag</span>\n<span><a href=\"#cb2-91\"></a> <span>let</span> file <span>=</span> <span>&quot;static/&quot;</span> <span>++</span> tag <span>++</span> <span>&quot;.org&quot;</span></span>\n<span><a href=\"#cb2-92\"></a> posts <span>&lt;-</span> recentFirst <span>=&lt;&lt;</span> filterM isPublished <span>=&lt;&lt;</span> loadAll <span>pattern</span></span>\n<span><a href=\"#cb2-93\"></a> <span>let</span> ctx <span>=</span></span>\n<span><a href=\"#cb2-94\"></a> constField <span>&quot;title&quot;</span> title</span>\n<span><a href=\"#cb2-95\"></a> <span>`mappend`</span> listField <span>&quot;posts&quot;</span> (postContext dateFormat dateFormat tags) (<span>return</span> posts)</span>\n<span><a href=\"#cb2-96\"></a> <span>`mappend`</span> defaultContext</span>\n<span><a href=\"#cb2-97\"></a> exists <span>&lt;-</span> unsafeCompiler <span>$</span> doesFileExist file</span>\n<span><a href=\"#cb2-98\"></a> <span>if</span> exists</span>\n<span><a href=\"#cb2-99\"></a> <span>then</span> <span>do</span></span>\n<span><a href=\"#cb2-100\"></a> body <span>&lt;-</span> load <span>$</span> fromFilePath file</span>\n<span><a href=\"#cb2-101\"></a> makeItem (itemBody body)</span>\n<span><a href=\"#cb2-102\"></a> <span>&gt;&gt;=</span> applyAsTemplate (indexContext posts (postContext dateFormat dateFormat tags))</span>\n<span><a href=\"#cb2-103\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> ctx</span>\n<span><a href=\"#cb2-104\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-105\"></a> <span>else</span></span>\n<span><a href=\"#cb2-106\"></a> makeItem <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-107\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/tag.html&quot;</span> ctx</span>\n<span><a href=\"#cb2-108\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> ctx</span>\n<span><a href=\"#cb2-109\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-110\"></a></span>\n<span><a href=\"#cb2-111\"></a> match <span>&quot;static/home.org&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-112\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-113\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-114\"></a> posts <span>&lt;-</span> recentFirst <span>=&lt;&lt;</span> filterM isPublished <span>=&lt;&lt;</span> loadAll articleFiles</span>\n<span><a href=\"#cb2-115\"></a> indexCompiler posts (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-116\"></a></span>\n<span><a href=\"#cb2-117\"></a> match <span>&quot;static/logs.org&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-118\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-119\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-120\"></a> <span>-- so that we pick up published from the title in postContext</span></span>\n<span><a href=\"#cb2-121\"></a> posts <span>&lt;-</span> <span>reverse</span> <span>&lt;$&gt;</span> loadAllSnapshots logFiles <span>&quot;feed&quot;</span></span>\n<span><a href=\"#cb2-122\"></a> indexCompiler posts (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-123\"></a></span>\n<span><a href=\"#cb2-124\"></a> match <span>&quot;static/news.org&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-125\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-126\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-127\"></a> posts <span>&lt;-</span> recentFirst <span>=&lt;&lt;</span> filterM isPublished <span>=&lt;&lt;</span> loadAll postFiles</span>\n<span><a href=\"#cb2-128\"></a> indexCompiler posts (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-129\"></a></span>\n<span><a href=\"#cb2-130\"></a> match <span>&quot;static/index.org&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-131\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-132\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-133\"></a> posts <span>&lt;-</span> filterM isNotDraft <span>=&lt;&lt;</span> loadAll (htmlFiles <span>.&amp;&amp;.</span> complement <span>&quot;static/index.org&quot;</span>)</span>\n<span><a href=\"#cb2-134\"></a> indexCompiler posts (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-135\"></a></span>\n<span><a href=\"#cb2-136\"></a> match <span>&quot;static/photos.org&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-137\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-138\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-139\"></a> photos <span>&lt;-</span> recentFirst <span>=&lt;&lt;</span> (loadAll (photoFiles <span>.&amp;&amp;.</span> hasNoVersion)<span> ::</span> <span>Compiler</span> [<span>Item</span> <span>CopyFile</span>])</span>\n<span><a href=\"#cb2-140\"></a> photosCompiler photos</span>\n<span><a href=\"#cb2-141\"></a></span>\n<span><a href=\"#cb2-142\"></a> match <span>&quot;papers.bib&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-143\"></a> route idRoute</span>\n<span><a href=\"#cb2-144\"></a> compile bibFileCompiler</span>\n<span><a href=\"#cb2-145\"></a></span>\n<span><a href=\"#cb2-146\"></a> match <span>&quot;static/papers.org&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-147\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-148\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-149\"></a> (<span>Bibs</span> bibFile) <span>&lt;-</span> loadBody <span>&quot;papers.bib&quot;</span><span> ::</span> <span>Compiler</span> <span>Bibs</span></span>\n<span><a href=\"#cb2-150\"></a> <span>let</span> sortedBibs <span>=</span> <span>reverse</span> <span>$</span> <span>fmap</span> <span>fst</span> <span>$</span> L.sortBy (comparing <span>snd</span>) <span>$</span> <span>fmap</span> (\\b <span>-&gt;</span> (b, bibDate b)) bibFile</span>\n<span><a href=\"#cb2-151\"></a> <span>let</span> bibsCtx <span>=</span> listField <span>&quot;papers&quot;</span> (bibContext dateFormat) (<span>mapM</span> makeItem sortedBibs)</span>\n<span><a href=\"#cb2-152\"></a> getResourceBody</span>\n<span><a href=\"#cb2-153\"></a> <span>&gt;&gt;=</span> renderPandoc</span>\n<span><a href=\"#cb2-154\"></a> <span>&gt;&gt;=</span> applyAsTemplate bibsCtx</span>\n<span><a href=\"#cb2-155\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> defaultContext</span>\n<span><a href=\"#cb2-156\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-157\"></a></span>\n<span><a href=\"#cb2-158\"></a> (<span>Bibs</span> bibs) <span>&lt;-</span> preprocess <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-159\"></a> parseBibFile <span>&lt;$&gt;</span> <span>readFile</span> <span>&quot;papers.bib&quot;</span></span>\n<span><a href=\"#cb2-160\"></a></span>\n<span><a href=\"#cb2-161\"></a> forM_ bibs <span>$</span> \\b <span>-&gt;</span></span>\n<span><a href=\"#cb2-162\"></a> create [fromCapture <span>&quot;papers/*.bib&quot;</span> <span>$</span> name b] <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-163\"></a> route idRoute</span>\n<span><a href=\"#cb2-164\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-165\"></a> bibFile <span>&lt;-</span> loadBody <span>&quot;papers.bib&quot;</span><span> ::</span> <span>Compiler</span> <span>Bibs</span></span>\n<span><a href=\"#cb2-166\"></a> makeItem b</span>\n<span><a href=\"#cb2-167\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/bib&quot;</span> (bibContext dateFormat)</span>\n<span><a href=\"#cb2-168\"></a></span>\n<span><a href=\"#cb2-169\"></a> matchMetadata articleFiles isNotDraftMeta <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-170\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-171\"></a> compile <span>$</span> postCompiler tags <span>&quot;templates/post.html&quot;</span></span>\n<span><a href=\"#cb2-172\"></a></span>\n<span><a href=\"#cb2-173\"></a> matchMetadata logFiles isNotDraftMeta <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-174\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-175\"></a> compile <span>$</span> postCompiler tags <span>&quot;templates/log.html&quot;</span></span>\n<span><a href=\"#cb2-176\"></a></span>\n<span><a href=\"#cb2-177\"></a> create [<span>&quot;atom.xml&quot;</span>] <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-178\"></a> route idRoute</span>\n<span><a href=\"#cb2-179\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-180\"></a> <span>let</span> feedContext <span>=</span> postContext dateFormat <span>&quot;%Y-%m-%dT%H:%M:%S%Q%Ez&quot;</span> tags <span>`mappend`</span> bodyField <span>&quot;content&quot;</span></span>\n<span><a href=\"#cb2-181\"></a> posts <span>&lt;-</span> recentFirst <span>=&lt;&lt;</span> filterM isPublished <span>=&lt;&lt;</span> loadAllSnapshots postFiles <span>&quot;feed&quot;</span></span>\n<span><a href=\"#cb2-182\"></a> atomTemplate <span>&lt;-</span> loadBody <span>&quot;templates/atom.xml&quot;</span></span>\n<span><a href=\"#cb2-183\"></a> atomItemTemplate <span>&lt;-</span> loadBody <span>&quot;templates/atom-item.xml&quot;</span></span>\n<span><a href=\"#cb2-184\"></a> renderAtomWithTemplates atomTemplate atomItemTemplate feedConfiguration feedContext posts</span>\n<span><a href=\"#cb2-185\"></a></span>\n<span><a href=\"#cb2-186\"></a> create [<span>&quot;sitemap.xml&quot;</span>] <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-187\"></a> route idRoute</span>\n<span><a href=\"#cb2-188\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-189\"></a> posts <span>&lt;-</span> loadAll htmlFiles</span>\n<span><a href=\"#cb2-190\"></a> <span>let</span> sitemapCtx <span>=</span></span>\n<span><a href=\"#cb2-191\"></a> listField <span>&quot;posts&quot;</span> (urlField <span>&quot;loc&quot;</span> <span>`mappend`</span> postContext dateFormat dateFormat tags) (<span>return</span> posts)</span>\n<span><a href=\"#cb2-192\"></a> <span>`mappend`</span> constField <span>&quot;root&quot;</span> <span>&quot;https://ryan.freumh.org&quot;</span></span>\n<span><a href=\"#cb2-193\"></a> <span>`mappend`</span> defaultContext</span>\n<span><a href=\"#cb2-194\"></a> makeItem <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-195\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/sitemap.xml&quot;</span> sitemapCtx</span>\n<span><a href=\"#cb2-196\"></a></span>\n<span><a href=\"#cb2-197\"></a> match <span>&quot;404.md&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-198\"></a> route <span>$</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-199\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-200\"></a> getResourceBody</span>\n<span><a href=\"#cb2-201\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> defaultContext</span>\n<span><a href=\"#cb2-202\"></a></span>\n<span><a href=\"#cb2-203\"></a> matchMetadata <span>&quot;static/**&quot;</span> isNotDraftMeta <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-204\"></a> route staticRoute</span>\n<span><a href=\"#cb2-205\"></a> compile copyFileCompiler</span>\n<span><a href=\"#cb2-206\"></a></span>\n<span><a href=\"#cb2-207\"></a> match <span>&quot;static/*.css&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-208\"></a> route staticRoute</span>\n<span><a href=\"#cb2-209\"></a> compile compressCssCompiler</span>\n<span><a href=\"#cb2-210\"></a></span>\n<span><a href=\"#cb2-211\"></a> match <span>&quot;ieee-with-url.csl&quot;</span> <span>$</span></span>\n<span><a href=\"#cb2-212\"></a> compile cslCompiler</span>\n<span><a href=\"#cb2-213\"></a></span>\n<span><a href=\"#cb2-214\"></a> match <span>&quot;references.bib&quot;</span> <span>$</span></span>\n<span><a href=\"#cb2-215\"></a> compile biblioCompiler</span>\n<span><a href=\"#cb2-216\"></a></span>\n<span><a href=\"#cb2-217\"></a> match <span>&quot;templates/*&quot;</span> <span>$</span></span>\n<span><a href=\"#cb2-218\"></a> compile templateBodyCompiler</span>\n<span><a href=\"#cb2-219\"></a></span>\n<span><a href=\"#cb2-220\"></a><span>staticRoute ::</span> <span>Routes</span></span>\n<span><a href=\"#cb2-221\"></a>staticRoute <span>=</span> gsubRoute <span>&quot;static/&quot;</span> (<span>const</span> <span>&quot;&quot;</span>)</span>\n<span><a href=\"#cb2-222\"></a></span>\n<span><a href=\"#cb2-223\"></a><span>indexCompiler ::</span> [<span>Item</span> a] <span>-&gt;</span> <span>Context</span> a <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-224\"></a>indexCompiler posts context <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-225\"></a> getResourceBody</span>\n<span><a href=\"#cb2-226\"></a> <span>&gt;&gt;=</span> transformRender</span>\n<span><a href=\"#cb2-227\"></a> <span>&gt;&gt;=</span> applyAsTemplate (indexContext posts context)</span>\n<span><a href=\"#cb2-228\"></a> <span>&gt;&gt;=</span> linkCompiler</span>\n<span><a href=\"#cb2-229\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> defaultContext</span>\n<span><a href=\"#cb2-230\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-231\"></a></span>\n<span><a href=\"#cb2-232\"></a><span>tagCompiler ::</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-233\"></a>tagCompiler <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-234\"></a> getResourceBody</span>\n<span><a href=\"#cb2-235\"></a> <span>&gt;&gt;=</span> bibRender <span>&quot;ieee-with-url.csl&quot;</span> <span>&quot;references.bib&quot;</span></span>\n<span><a href=\"#cb2-236\"></a> <span>&gt;&gt;=</span> linkCompiler</span>\n<span><a href=\"#cb2-237\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-238\"></a></span>\n<span><a href=\"#cb2-239\"></a><span>postCompiler ::</span> <span>Tags</span> <span>-&gt;</span> <span>Identifier</span> <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-240\"></a>postCompiler tags template <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-241\"></a> getResourceBody</span>\n<span><a href=\"#cb2-242\"></a> <span>&gt;&gt;=</span> saveSnapshot <span>&quot;body&quot;</span></span>\n<span><a href=\"#cb2-243\"></a> <span>&gt;&gt;=</span> bibRenderFeed <span>&quot;ieee-with-url.csl&quot;</span> <span>&quot;references.bib&quot;</span></span>\n<span><a href=\"#cb2-244\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate template (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-245\"></a> <span>&gt;&gt;=</span> linkCompiler</span>\n<span><a href=\"#cb2-246\"></a> <span>&gt;&gt;=</span> saveSnapshot <span>&quot;feed&quot;</span></span>\n<span><a href=\"#cb2-247\"></a> getResourceBody</span>\n<span><a href=\"#cb2-248\"></a> <span>&gt;&gt;=</span> saveSnapshot <span>&quot;body&quot;</span></span>\n<span><a href=\"#cb2-249\"></a> <span>&gt;&gt;=</span> bibRender <span>&quot;ieee-with-url.csl&quot;</span> <span>&quot;references.bib&quot;</span></span>\n<span><a href=\"#cb2-250\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate template (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-251\"></a> <span>&gt;&gt;=</span> linkCompiler</span>\n<span><a href=\"#cb2-252\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-253\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-254\"></a></span>\n<span><a href=\"#cb2-255\"></a><span>linkCompiler ::</span> <span>Item</span> <span>String</span> <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-256\"></a>linkCompiler <span>=</span> <span>pure</span> <span>.</span> <span>fmap</span> (withUrls rewriteLinks)</span>\n<span><a href=\"#cb2-257\"></a></span>\n<span><a href=\"#cb2-258\"></a><span>photosCompiler ::</span> [<span>Item</span> a] <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-259\"></a>photosCompiler photos <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-260\"></a> getResourceBody</span>\n<span><a href=\"#cb2-261\"></a> <span>&gt;&gt;=</span> renderPandoc</span>\n<span><a href=\"#cb2-262\"></a> <span>&gt;&gt;=</span> applyAsTemplate (photosContext photos)</span>\n<span><a href=\"#cb2-263\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> defaultContext</span>\n<span><a href=\"#cb2-264\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-265\"></a></span>\n<span><a href=\"#cb2-266\"></a><span>readerOptions ::</span> <span>ReaderOptions</span></span>\n<span><a href=\"#cb2-267\"></a>readerOptions <span>=</span></span>\n<span><a href=\"#cb2-268\"></a> def</span>\n<span><a href=\"#cb2-269\"></a> { readerExtensions <span>=</span> <span>foldr</span> enableExtension pandocExtensions [<span>Ext_citations</span>, <span>Ext_smart</span>]</span>\n<span><a href=\"#cb2-270\"></a> }</span>\n<span><a href=\"#cb2-271\"></a></span>\n<span><a href=\"#cb2-272\"></a><span>writerOptions ::</span> <span>WriterOptions</span></span>\n<span><a href=\"#cb2-273\"></a>writerOptions <span>=</span></span>\n<span><a href=\"#cb2-274\"></a> def</span>\n<span><a href=\"#cb2-275\"></a> { writerExtensions <span>=</span> enableExtension <span>Ext_smart</span> pandocExtensions,</span>\n<span><a href=\"#cb2-276\"></a> writerHighlightStyle <span>=</span> <span>Just</span> pygments,</span>\n<span><a href=\"#cb2-277\"></a> writerCiteMethod <span>=</span> <span>Citeproc</span></span>\n<span><a href=\"#cb2-278\"></a> }</span>\n<span><a href=\"#cb2-279\"></a></span>\n<span><a href=\"#cb2-280\"></a><span>transformRender ::</span> <span>Item</span> <span>String</span> <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-281\"></a>transformRender <span>=</span></span>\n<span><a href=\"#cb2-282\"></a> renderPandocWithTransformM defaultHakyllReaderOptions defaultHakyllWriterOptions pandocTransform</span>\n<span><a href=\"#cb2-283\"></a></span>\n<span><a href=\"#cb2-284\"></a><span>bibRender ::</span> <span>String</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Item</span> <span>String</span> <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-285\"></a>bibRender cslFileName bibFileName pandoc <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-286\"></a> csl <span>&lt;-</span> load <span>$</span> fromFilePath cslFileName</span>\n<span><a href=\"#cb2-287\"></a> bib <span>&lt;-</span> load <span>$</span> fromFilePath bibFileName</span>\n<span><a href=\"#cb2-288\"></a> <span>let</span> transform <span>=</span></span>\n<span><a href=\"#cb2-289\"></a> withItemBody</span>\n<span><a href=\"#cb2-290\"></a> ( \\(<span>Pandoc</span> (<span>Meta</span> meta) bs) <span>-&gt;</span></span>\n<span><a href=\"#cb2-291\"></a> <span>pure</span> <span>$</span></span>\n<span><a href=\"#cb2-292\"></a> <span>Pandoc</span></span>\n<span><a href=\"#cb2-293\"></a> (<span>Meta</span> <span>$</span> M.insert <span>&quot;link-citations&quot;</span> (<span>MetaBool</span> <span>True</span>) meta)</span>\n<span><a href=\"#cb2-294\"></a> bs</span>\n<span><a href=\"#cb2-295\"></a> )</span>\n<span><a href=\"#cb2-296\"></a> <span>&gt;=&gt;</span> processPandocBiblios csl [bib]</span>\n<span><a href=\"#cb2-297\"></a> <span>&gt;=&gt;</span> withItemBody pandocTransform</span>\n<span><a href=\"#cb2-298\"></a> renderPandocItemWithTransformM readerOptions writerOptions transform pandoc</span>\n<span><a href=\"#cb2-299\"></a></span>\n<span><a href=\"#cb2-300\"></a><span>bibRenderFeed ::</span> <span>String</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Item</span> <span>String</span> <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-301\"></a>bibRenderFeed cslFileName bibFileName pandoc <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-302\"></a> csl <span>&lt;-</span> load <span>$</span> fromFilePath cslFileName</span>\n<span><a href=\"#cb2-303\"></a> bib <span>&lt;-</span> load <span>$</span> fromFilePath bibFileName</span>\n<span><a href=\"#cb2-304\"></a> <span>let</span> transform <span>=</span></span>\n<span><a href=\"#cb2-305\"></a> withItemBody</span>\n<span><a href=\"#cb2-306\"></a> ( \\(<span>Pandoc</span> (<span>Meta</span> meta) bs) <span>-&gt;</span></span>\n<span><a href=\"#cb2-307\"></a> <span>pure</span> <span>$</span></span>\n<span><a href=\"#cb2-308\"></a> <span>Pandoc</span></span>\n<span><a href=\"#cb2-309\"></a> (<span>Meta</span> <span>$</span> M.insert <span>&quot;link-citations&quot;</span> (<span>MetaBool</span> <span>True</span>) meta)</span>\n<span><a href=\"#cb2-310\"></a> bs</span>\n<span><a href=\"#cb2-311\"></a> )</span>\n<span><a href=\"#cb2-312\"></a> <span>&gt;=&gt;</span> processPandocBiblios csl [bib]</span>\n<span><a href=\"#cb2-313\"></a> <span>&gt;=&gt;</span> withItemBody pandocTransformFeed</span>\n<span><a href=\"#cb2-314\"></a> renderPandocItemWithTransformM readerOptions writerOptions transform pandoc</span>\n<span><a href=\"#cb2-315\"></a></span>\n<span><a href=\"#cb2-316\"></a><span>pandocTransform ::</span> <span>Pandoc</span> <span>-&gt;</span> <span>Compiler</span> <span>Pandoc</span></span>\n<span><a href=\"#cb2-317\"></a>pandocTransform <span>=</span></span>\n<span><a href=\"#cb2-318\"></a> unsafeCompiler</span>\n<span><a href=\"#cb2-319\"></a> <span>.</span> runIOorExplode</span>\n<span><a href=\"#cb2-320\"></a> <span>.</span> ( applyFilter def [] <span>&quot;scripts/org-keywords.lua&quot;</span></span>\n<span><a href=\"#cb2-321\"></a> <span>&gt;=&gt;</span> applyFilter def [] <span>&quot;scripts/elem-ids.lua&quot;</span></span>\n<span><a href=\"#cb2-322\"></a> <span>&gt;=&gt;</span> applyFilter def [] <span>&quot;scripts/footnote-commas.lua&quot;</span></span>\n<span><a href=\"#cb2-323\"></a> <span>&gt;=&gt;</span> applyFilter def [] <span>&quot;scripts/anchor-links.lua&quot;</span></span>\n<span><a href=\"#cb2-324\"></a> )</span>\n<span><a href=\"#cb2-325\"></a></span>\n<span><a href=\"#cb2-326\"></a><span>pandocTransformFeed ::</span> <span>Pandoc</span> <span>-&gt;</span> <span>Compiler</span> <span>Pandoc</span></span>\n<span><a href=\"#cb2-327\"></a>pandocTransformFeed <span>=</span></span>\n<span><a href=\"#cb2-328\"></a> unsafeCompiler</span>\n<span><a href=\"#cb2-329\"></a> <span>.</span> runIOorExplode</span>\n<span><a href=\"#cb2-330\"></a> <span>.</span> ( applyFilter def [] <span>&quot;scripts/org-keywords.lua&quot;</span></span>\n<span><a href=\"#cb2-331\"></a> <span>&gt;=&gt;</span> applyFilter def [] <span>&quot;scripts/elem-ids.lua&quot;</span></span>\n<span><a href=\"#cb2-332\"></a> <span>&gt;=&gt;</span> applyFilter def [] <span>&quot;scripts/footnote-commas.lua&quot;</span></span>\n<span><a href=\"#cb2-333\"></a> )</span>\n<span><a href=\"#cb2-334\"></a></span>\n<span><a href=\"#cb2-335\"></a><span>indexContext ::</span> [<span>Item</span> a] <span>-&gt;</span> <span>Context</span> a <span>-&gt;</span> <span>Context</span> <span>String</span></span>\n<span><a href=\"#cb2-336\"></a>indexContext posts itemContext <span>=</span></span>\n<span><a href=\"#cb2-337\"></a> listField <span>&quot;posts&quot;</span> itemContext (<span>return</span> posts)</span>\n<span><a href=\"#cb2-338\"></a> <span>`mappend`</span> defaultContext</span>\n<span><a href=\"#cb2-339\"></a></span>\n<span><a href=\"#cb2-340\"></a><span>photosContext ::</span> [<span>Item</span> a] <span>-&gt;</span> <span>Context</span> <span>String</span></span>\n<span><a href=\"#cb2-341\"></a>photosContext photos <span>=</span></span>\n<span><a href=\"#cb2-342\"></a> listField <span>&quot;photos&quot;</span> photoContext (<span>return</span> photos)</span>\n<span><a href=\"#cb2-343\"></a> <span>`mappend`</span> defaultContext</span>\n<span><a href=\"#cb2-344\"></a></span>\n<span><a href=\"#cb2-345\"></a><span>postContext ::</span> <span>String</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Tags</span> <span>-&gt;</span> <span>Context</span> <span>String</span></span>\n<span><a href=\"#cb2-346\"></a>postContext titleDateFormat dateFormat tags <span>=</span></span>\n<span><a href=\"#cb2-347\"></a> field <span>&quot;prev&quot;</span> (adjacentLogField (<span>-</span><span>1</span>) dateFormat)</span>\n<span><a href=\"#cb2-348\"></a> <span>`mappend`</span> field <span>&quot;next&quot;</span> (adjacentLogField <span>1</span> dateFormat)</span>\n<span><a href=\"#cb2-349\"></a> <span>`mappend`</span> dateFieldFromTitle <span>&quot;title&quot;</span> titleDateFormat</span>\n<span><a href=\"#cb2-350\"></a> <span>`mappend`</span> dateField <span>&quot;published&quot;</span> dateFormat</span>\n<span><a href=\"#cb2-351\"></a> <span>`mappend`</span> myDateField <span>&quot;updated&quot;</span> dateFormat</span>\n<span><a href=\"#cb2-352\"></a> <span>`mappend`</span> myTagsField <span>&quot;tags&quot;</span> tags</span>\n<span><a href=\"#cb2-353\"></a> <span>`mappend`</span> defaultContext</span>\n<span><a href=\"#cb2-354\"></a></span>\n<span><a href=\"#cb2-355\"></a><span>-- https://github.com/emmanueltouzery/hsexif/issues/23#issuecomment-2835135828</span></span>\n<span><a href=\"#cb2-356\"></a>formatNumeric f (<span>ExifRational</span> num den) <span>=</span> f num den <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-357\"></a>formatNumeric f (<span>ExifRationalList</span> values) <span>=</span> go values <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-358\"></a> <span>where</span></span>\n<span><a href=\"#cb2-359\"></a> go [] <span>=</span> <span>id</span></span>\n<span><a href=\"#cb2-360\"></a> go [(n, d)] <span>=</span> f n d</span>\n<span><a href=\"#cb2-361\"></a> go ((n, d) <span>:</span> ns) <span>=</span> f n d <span>.</span> <span>showString</span> <span>&quot;, &quot;</span> <span>.</span> go ns</span>\n<span><a href=\"#cb2-362\"></a>formatNumeric _ value <span>=</span> <span>show</span> value</span>\n<span><a href=\"#cb2-363\"></a></span>\n<span><a href=\"#cb2-364\"></a><span>formatAsNumber ::</span> <span>Int</span> <span>-&gt;</span> <span>ExifValue</span> <span>-&gt;</span> <span>String</span></span>\n<span><a href=\"#cb2-365\"></a>formatAsNumber n <span>=</span> formatNumeric fmt</span>\n<span><a href=\"#cb2-366\"></a> <span>where</span></span>\n<span><a href=\"#cb2-367\"></a> fmt num den s <span>=</span> trim0 (fltString num den) <span>++</span> s</span>\n<span><a href=\"#cb2-368\"></a> trim0 <span>=</span> <span>reverse</span> <span>.</span> <span>dropWhile</span> (<span>'.'</span> <span>==</span>) <span>.</span> <span>dropWhile</span> (<span>'0'</span> <span>==</span>) <span>.</span> <span>reverse</span></span>\n<span><a href=\"#cb2-369\"></a> fltString num den <span>=</span> showFFloat (<span>Just</span> n) (<span>fromIntegral</span> num <span>/</span> <span>fromIntegral</span><span> den ::</span> <span>Double</span>) <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-370\"></a></span>\n<span><a href=\"#cb2-371\"></a><span>ppExposureTime ::</span> <span>ExifValue</span> <span>-&gt;</span> <span>String</span></span>\n<span><a href=\"#cb2-372\"></a>ppExposureTime v<span>@</span>(<span>ExifRational</span> num den) <span>=</span></span>\n<span><a href=\"#cb2-373\"></a> <span>let</span> seconds <span>=</span> <span>fromIntegral</span> num <span>/</span> (<span>fromIntegral</span><span> den ::</span> <span>Double</span>)</span>\n<span><a href=\"#cb2-374\"></a> value</span>\n<span><a href=\"#cb2-375\"></a> <span>|</span> seconds <span>&lt;=</span> <span>0.25</span> <span>&amp;&amp;</span> seconds <span>&gt;</span> <span>0</span> <span>=</span> <span>&quot;1/&quot;</span> <span>++</span> <span>show</span> (<span>round</span> (<span>1</span> <span>/</span> seconds)<span> ::</span> <span>Int</span>)</span>\n<span><a href=\"#cb2-376\"></a> <span>|</span> <span>otherwise</span> <span>=</span> formatAsNumber <span>1</span> v</span>\n<span><a href=\"#cb2-377\"></a> <span>in</span> T.unpack <span>$</span> T.append (T.pack value) <span>&quot; sec.&quot;</span></span>\n<span><a href=\"#cb2-378\"></a>ppExposureTime v <span>=</span> <span>show</span> v</span>\n<span><a href=\"#cb2-379\"></a></span>\n<span><a href=\"#cb2-380\"></a><span>photoContext ::</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-381\"></a>photoContext <span>=</span></span>\n<span><a href=\"#cb2-382\"></a> dateField <span>&quot;published&quot;</span> dateFormat</span>\n<span><a href=\"#cb2-383\"></a> <span>`mappend`</span> urlField <span>&quot;url&quot;</span></span>\n<span><a href=\"#cb2-384\"></a> <span>`mappend`</span> pathField <span>&quot;path&quot;</span></span>\n<span><a href=\"#cb2-385\"></a> <span>`mappend`</span> titleField <span>&quot;title&quot;</span></span>\n<span><a href=\"#cb2-386\"></a> <span>`mappend`</span> thumbnailField <span>&quot;thumb&quot;</span></span>\n<span><a href=\"#cb2-387\"></a> <span>`mappend`</span> videoField <span>&quot;video&quot;</span></span>\n<span><a href=\"#cb2-388\"></a> <span>`mappend`</span> exifDateField <span>&quot;published&quot;</span> dateFormat</span>\n<span><a href=\"#cb2-389\"></a> <span>`mappend`</span> exifLatField <span>&quot;lat&quot;</span></span>\n<span><a href=\"#cb2-390\"></a> <span>`mappend`</span> exifLongField <span>&quot;lon&quot;</span></span>\n<span><a href=\"#cb2-391\"></a> <span>`mappend`</span> exifField <span>&quot;make&quot;</span> make <span>show</span></span>\n<span><a href=\"#cb2-392\"></a> <span>`mappend`</span> exifField <span>&quot;model&quot;</span> model <span>show</span></span>\n<span><a href=\"#cb2-393\"></a> <span>`mappend`</span> exifField <span>&quot;focallength&quot;</span> focalLength (formatAsFloatingPoint <span>2</span>)</span>\n<span><a href=\"#cb2-394\"></a> <span>`mappend`</span> exifField <span>&quot;aperture&quot;</span> apertureValue (formatAsFloatingPoint <span>2</span>)</span>\n<span><a href=\"#cb2-395\"></a> <span>`mappend`</span> exifField <span>&quot;exposure&quot;</span> exposureTime ppExposureTime</span>\n<span><a href=\"#cb2-396\"></a> <span>`mappend`</span> exifField <span>&quot;iso&quot;</span> isoSpeedRatings <span>show</span></span>\n<span><a href=\"#cb2-397\"></a> <span>`mappend`</span> locationField <span>&quot;loc&quot;</span></span>\n<span><a href=\"#cb2-398\"></a></span>\n<span><a href=\"#cb2-399\"></a><span>exifField ::</span> <span>String</span> <span>-&gt;</span> <span>ExifTag</span> <span>-&gt;</span> (<span>ExifValue</span> <span>-&gt;</span> <span>String</span>) <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-400\"></a>exifField key tag <span>print</span> <span>=</span></span>\n<span><a href=\"#cb2-401\"></a> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-402\"></a> metadata <span>&lt;-</span> exifMetadata item</span>\n<span><a href=\"#cb2-403\"></a> <span>case</span> M.lookup tag metadata <span>of</span></span>\n<span><a href=\"#cb2-404\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-405\"></a> <span>Just</span> value <span>-&gt;</span> <span>return</span> <span>$</span> <span>print</span> value</span>\n<span><a href=\"#cb2-406\"></a></span>\n<span><a href=\"#cb2-407\"></a><span>exifLatField ::</span> <span>String</span> <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-408\"></a>exifLatField key <span>=</span></span>\n<span><a href=\"#cb2-409\"></a> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-410\"></a> metadata <span>&lt;-</span> exifMetadata item</span>\n<span><a href=\"#cb2-411\"></a> <span>case</span> getGpsLatitudeLongitude metadata <span>of</span></span>\n<span><a href=\"#cb2-412\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-413\"></a> <span>Just</span> (lat, _) <span>-&gt;</span> <span>return</span> <span>$</span> <span>show</span> lat</span>\n<span><a href=\"#cb2-414\"></a></span>\n<span><a href=\"#cb2-415\"></a><span>exifLongField ::</span> <span>String</span> <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-416\"></a>exifLongField key <span>=</span></span>\n<span><a href=\"#cb2-417\"></a> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-418\"></a> metadata <span>&lt;-</span> exifMetadata item</span>\n<span><a href=\"#cb2-419\"></a> <span>case</span> getGpsLatitudeLongitude metadata <span>of</span></span>\n<span><a href=\"#cb2-420\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-421\"></a> <span>Just</span> (_, lon) <span>-&gt;</span> <span>return</span> <span>$</span> <span>show</span> lon</span>\n<span><a href=\"#cb2-422\"></a></span>\n<span><a href=\"#cb2-423\"></a><span>exifDateField ::</span> <span>String</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-424\"></a>exifDateField key format <span>=</span></span>\n<span><a href=\"#cb2-425\"></a> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-426\"></a> metadata <span>&lt;-</span> exifMetadata item</span>\n<span><a href=\"#cb2-427\"></a> <span>case</span> getDateTimeOriginal metadata <span>of</span></span>\n<span><a href=\"#cb2-428\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-429\"></a> <span>Just</span> date <span>-&gt;</span> <span>return</span> <span>$</span> formatTime defaultTimeLocale format date</span>\n<span><a href=\"#cb2-430\"></a></span>\n<span><a href=\"#cb2-431\"></a><span>-- </span><span>TODO</span><span> don't load metadata individually for each field</span></span>\n<span><a href=\"#cb2-432\"></a><span>exifMetadata ::</span> <span>Item</span> a <span>-&gt;</span> <span>Compiler</span> (<span>M.Map</span> <span>ExifTag</span> <span>ExifValue</span>)</span>\n<span><a href=\"#cb2-433\"></a>exifMetadata item <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-434\"></a> <span>let</span> identifier <span>=</span> itemIdentifier item</span>\n<span><a href=\"#cb2-435\"></a> exifData <span>&lt;-</span> unsafeCompiler (parseFileExif (toFilePath identifier))</span>\n<span><a href=\"#cb2-436\"></a> <span>return</span> <span>$</span> fromRight M.empty exifData</span>\n<span><a href=\"#cb2-437\"></a></span>\n<span><a href=\"#cb2-438\"></a><span>data</span> <span>PhotoLocation</span> <span>=</span> <span>PhotoLocation</span></span>\n<span><a href=\"#cb2-439\"></a> {<span> displayName ::</span> <span>T.Text</span>,</span>\n<span><a href=\"#cb2-440\"></a><span> addressMap ::</span> <span>HM.HashMap</span> <span>T.Text</span> <span>T.Text</span></span>\n<span><a href=\"#cb2-441\"></a> }</span>\n<span><a href=\"#cb2-442\"></a> <span>deriving</span> (<span>Show</span>)</span>\n<span><a href=\"#cb2-443\"></a></span>\n<span><a href=\"#cb2-444\"></a><span>instance</span> <span>FromJSON</span> <span>PhotoLocation</span> <span>where</span></span>\n<span><a href=\"#cb2-445\"></a> parseJSON <span>=</span> withObject <span>&quot;PhotoLocation&quot;</span> <span>$</span> \\v <span>-&gt;</span></span>\n<span><a href=\"#cb2-446\"></a> <span>PhotoLocation</span></span>\n<span><a href=\"#cb2-447\"></a> <span>&lt;$&gt;</span> v <span>.:</span> <span>&quot;display_name&quot;</span></span>\n<span><a href=\"#cb2-448\"></a> <span>&lt;*&gt;</span> v <span>.:</span> <span>&quot;address&quot;</span></span>\n<span><a href=\"#cb2-449\"></a></span>\n<span><a href=\"#cb2-450\"></a><span>readCachedLocation ::</span> <span>FilePath</span> <span>-&gt;</span> <span>IO</span> (<span>Either</span> <span>String</span> <span>PhotoLocation</span>)</span>\n<span><a href=\"#cb2-451\"></a>readCachedLocation photoPath <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-452\"></a> <span>let</span> cacheFile <span>=</span> <span>&quot;reverse-geocoding/&quot;</span> <span>++</span> takeFileName photoPath <span>++</span> <span>&quot;.json&quot;</span></span>\n<span><a href=\"#cb2-453\"></a> exists <span>&lt;-</span> doesFileExist cacheFile</span>\n<span><a href=\"#cb2-454\"></a> <span>if</span> <span>not</span> exists</span>\n<span><a href=\"#cb2-455\"></a> <span>then</span> <span>return</span> <span>$</span> <span>Left</span> <span>&quot;Cache file not found&quot;</span></span>\n<span><a href=\"#cb2-456\"></a> <span>else</span> eitherDecode <span>&lt;$&gt;</span> BSL.readFile cacheFile</span>\n<span><a href=\"#cb2-457\"></a></span>\n<span><a href=\"#cb2-458\"></a><span>formatLocation ::</span> <span>HM.HashMap</span> <span>T.Text</span> <span>T.Text</span> <span>-&gt;</span> <span>T.Text</span></span>\n<span><a href=\"#cb2-459\"></a>formatLocation m <span>=</span></span>\n<span><a href=\"#cb2-460\"></a> <span>let</span> country <span>=</span> HM.lookup <span>&quot;country&quot;</span> m</span>\n<span><a href=\"#cb2-461\"></a> city <span>=</span> HM.lookup <span>&quot;city&quot;</span> m</span>\n<span><a href=\"#cb2-462\"></a> state_district <span>=</span> HM.lookup <span>&quot;state_district&quot;</span> m</span>\n<span><a href=\"#cb2-463\"></a> heirarchy</span>\n<span><a href=\"#cb2-464\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;United States&quot;</span> <span>&amp;&amp;</span> city <span>==</span> <span>Just</span> <span>&quot;New York&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-465\"></a> [ [<span>&quot;borough&quot;</span>],</span>\n<span><a href=\"#cb2-466\"></a> [<span>&quot;state&quot;</span>],</span>\n<span><a href=\"#cb2-467\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-468\"></a> ]</span>\n<span><a href=\"#cb2-469\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;United States&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-470\"></a> [ [<span>&quot;city&quot;</span>, <span>&quot;town&quot;</span>, <span>&quot;village&quot;</span>, <span>&quot;road&quot;</span>],</span>\n<span><a href=\"#cb2-471\"></a> [<span>&quot;state&quot;</span>],</span>\n<span><a href=\"#cb2-472\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-473\"></a> ]</span>\n<span><a href=\"#cb2-474\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;United Kingdom&quot;</span> <span>&amp;&amp;</span> city <span>==</span> <span>Just</span> <span>&quot;London&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-475\"></a> [ [<span>&quot;suburb&quot;</span>],</span>\n<span><a href=\"#cb2-476\"></a> [<span>&quot;city&quot;</span>],</span>\n<span><a href=\"#cb2-477\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-478\"></a> ]</span>\n<span><a href=\"#cb2-479\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;United Kingdom&quot;</span> <span>&amp;&amp;</span> state_district <span>==</span> <span>Just</span> <span>&quot;Greater London&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-480\"></a> [ [<span>&quot;city&quot;</span>],</span>\n<span><a href=\"#cb2-481\"></a> [<span>&quot;state_district&quot;</span>],</span>\n<span><a href=\"#cb2-482\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-483\"></a> ]</span>\n<span><a href=\"#cb2-484\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;United Kingdom&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-485\"></a> [ [<span>&quot;city&quot;</span>, <span>&quot;town&quot;</span>, <span>&quot;village&quot;</span>],</span>\n<span><a href=\"#cb2-486\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-487\"></a> ]</span>\n<span><a href=\"#cb2-488\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;France&quot;</span> <span>&amp;&amp;</span> city <span>==</span> <span>Just</span> <span>&quot;Paris&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-489\"></a> [ [<span>&quot;suburb&quot;</span>],</span>\n<span><a href=\"#cb2-490\"></a> [<span>&quot;city&quot;</span>],</span>\n<span><a href=\"#cb2-491\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-492\"></a> ]</span>\n<span><a href=\"#cb2-493\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;Italy&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-494\"></a> [ [<span>&quot;quarter&quot;</span>],</span>\n<span><a href=\"#cb2-495\"></a> [<span>&quot;city&quot;</span>, <span>&quot;town&quot;</span>, <span>&quot;village&quot;</span>],</span>\n<span><a href=\"#cb2-496\"></a> [<span>&quot;state&quot;</span>],</span>\n<span><a href=\"#cb2-497\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-498\"></a> ]</span>\n<span><a href=\"#cb2-499\"></a> <span>|</span> <span>otherwise</span> <span>=</span></span>\n<span><a href=\"#cb2-500\"></a> [ [<span>&quot;historic&quot;</span>],</span>\n<span><a href=\"#cb2-501\"></a> [<span>&quot;city&quot;</span>, <span>&quot;state&quot;</span>, <span>&quot;region&quot;</span>, <span>&quot;town&quot;</span>],</span>\n<span><a href=\"#cb2-502\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-503\"></a> ]</span>\n<span><a href=\"#cb2-504\"></a> lookupFirst ks <span>=</span> listToMaybe <span>$</span> mapMaybe (<span>`HM.lookup`</span> m) ks</span>\n<span><a href=\"#cb2-505\"></a> fields <span>=</span> <span>map</span> lookupFirst heirarchy</span>\n<span><a href=\"#cb2-506\"></a> <span>in</span> T.intercalate <span>&quot;, &quot;</span> (catMaybes fields)</span>\n<span><a href=\"#cb2-507\"></a></span>\n<span><a href=\"#cb2-508\"></a><span>locationField ::</span> <span>String</span> <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-509\"></a>locationField key <span>=</span> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-510\"></a> <span>let</span> fp <span>=</span> toFilePath (itemIdentifier item)</span>\n<span><a href=\"#cb2-511\"></a> eLoc <span>&lt;-</span> unsafeCompiler <span>$</span> readCachedLocation fp</span>\n<span><a href=\"#cb2-512\"></a> <span>case</span> eLoc <span>of</span></span>\n<span><a href=\"#cb2-513\"></a> <span>Left</span> _ <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-514\"></a> <span>Right</span> loc <span>-&gt;</span></span>\n<span><a href=\"#cb2-515\"></a> <span>let</span> txt <span>=</span> formatLocation (addressMap loc)</span>\n<span><a href=\"#cb2-516\"></a> <span>in</span> <span>if</span> T.null txt <span>then</span> noResult <span>&quot;&quot;</span> <span>else</span> <span>return</span> (T.unpack txt)</span>\n<span><a href=\"#cb2-517\"></a></span>\n<span><a href=\"#cb2-518\"></a><span>myDateField ::</span> <span>String</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Context</span> <span>String</span></span>\n<span><a href=\"#cb2-519\"></a>myDateField name format <span>=</span></span>\n<span><a href=\"#cb2-520\"></a> field name <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-521\"></a> metadata <span>&lt;-</span> getMetadata (itemIdentifier item)</span>\n<span><a href=\"#cb2-522\"></a> <span>let</span><span> date ::</span> <span>Maybe</span> <span>UTCTime</span></span>\n<span><a href=\"#cb2-523\"></a> date <span>=</span> lookupString name metadata <span>&gt;&gt;=</span> parseTimeM <span>True</span> defaultTimeLocale <span>&quot;%Y-%m-%d&quot;</span></span>\n<span><a href=\"#cb2-524\"></a> <span>case</span> date <span>of</span></span>\n<span><a href=\"#cb2-525\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-526\"></a> <span>Just</span> date <span>-&gt;</span> <span>return</span> <span>$</span> formatTime defaultTimeLocale format date</span>\n<span><a href=\"#cb2-527\"></a></span>\n<span><a href=\"#cb2-528\"></a><span>dateFieldFromTitle ::</span> <span>String</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Context</span> <span>String</span></span>\n<span><a href=\"#cb2-529\"></a>dateFieldFromTitle key format <span>=</span></span>\n<span><a href=\"#cb2-530\"></a> field key <span>$</span> \\item <span>-&gt;</span></span>\n<span><a href=\"#cb2-531\"></a> <span>case</span> dateFromTitle item <span>of</span></span>\n<span><a href=\"#cb2-532\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-533\"></a> <span>Just</span> date <span>-&gt;</span></span>\n<span><a href=\"#cb2-534\"></a> <span>return</span> <span>$</span> formatTime defaultTimeLocale format date</span>\n<span><a href=\"#cb2-535\"></a></span>\n<span><a href=\"#cb2-536\"></a><span>thumbnailField ::</span> <span>String</span> <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-537\"></a>thumbnailField key <span>=</span> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-538\"></a> mRoute <span>&lt;-</span> getRoute (itemIdentifier item)</span>\n<span><a href=\"#cb2-539\"></a> <span>case</span> mRoute <span>of</span></span>\n<span><a href=\"#cb2-540\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-541\"></a> <span>Just</span> url <span>-&gt;</span></span>\n<span><a href=\"#cb2-542\"></a> <span>if</span> <span>&quot;.mp4&quot;</span> <span>`L.isSuffixOf`</span> url</span>\n<span><a href=\"#cb2-543\"></a> <span>then</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-544\"></a> <span>else</span></span>\n<span><a href=\"#cb2-545\"></a> <span>return</span> <span>$</span></span>\n<span><a href=\"#cb2-546\"></a> T.unpack <span>$</span></span>\n<span><a href=\"#cb2-547\"></a> T.replace <span>&quot;photos/&quot;</span> <span>&quot;photos/thumb/&quot;</span> (T.pack url)</span>\n<span><a href=\"#cb2-548\"></a></span>\n<span><a href=\"#cb2-549\"></a><span>videoField ::</span> <span>String</span> <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-550\"></a>videoField key <span>=</span> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-551\"></a> mRoute <span>&lt;-</span> getRoute (itemIdentifier item)</span>\n<span><a href=\"#cb2-552\"></a> <span>case</span> mRoute <span>of</span></span>\n<span><a href=\"#cb2-553\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-554\"></a> <span>Just</span> url <span>-&gt;</span></span>\n<span><a href=\"#cb2-555\"></a> <span>if</span> <span>&quot;.mp4&quot;</span> <span>`L.isSuffixOf`</span> url</span>\n<span><a href=\"#cb2-556\"></a> <span>then</span></span>\n<span><a href=\"#cb2-557\"></a> <span>return</span> <span>$</span></span>\n<span><a href=\"#cb2-558\"></a> T.unpack <span>$</span></span>\n<span><a href=\"#cb2-559\"></a> T.replace <span>&quot;static/photos/&quot;</span> <span>&quot;photos/&quot;</span> (T.pack url)</span>\n<span><a href=\"#cb2-560\"></a> <span>else</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-561\"></a></span>\n<span><a href=\"#cb2-562\"></a><span>myTagsField ::</span> <span>String</span> <span>-&gt;</span> <span>Tags</span> <span>-&gt;</span> <span>Context</span> <span>String</span></span>\n<span><a href=\"#cb2-563\"></a>myTagsField key tags <span>=</span> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-564\"></a> tags' <span>&lt;-</span> getTags <span>$</span> itemIdentifier item</span>\n<span><a href=\"#cb2-565\"></a> <span>if</span> <span>null</span> tags'</span>\n<span><a href=\"#cb2-566\"></a> <span>then</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-567\"></a> <span>else</span> <span>do</span></span>\n<span><a href=\"#cb2-568\"></a> links <span>&lt;-</span> forM tags' <span>$</span> \\tag <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-569\"></a> route' <span>&lt;-</span> getRoute <span>$</span> tagsMakeId tags tag</span>\n<span><a href=\"#cb2-570\"></a> <span>return</span> <span>$</span> simpleRenderLink tag route'</span>\n<span><a href=\"#cb2-571\"></a> <span>return</span> <span>$</span> renderHtml <span>$</span> <span>mconcat</span> <span>.</span> L.intersperse <span>&quot;, &quot;</span> <span>$</span> catMaybes links</span>\n<span><a href=\"#cb2-572\"></a></span>\n<span><a href=\"#cb2-573\"></a><span>renderTag ::</span> <span>String</span> <span>-&gt;</span> <span>Maybe</span> <span>FilePath</span> <span>-&gt;</span> <span>Maybe</span> <span>H.Html</span></span>\n<span><a href=\"#cb2-574\"></a>renderTag _ <span>Nothing</span> <span>=</span> <span>Nothing</span></span>\n<span><a href=\"#cb2-575\"></a>renderTag tag (<span>Just</span> filePath) <span>=</span></span>\n<span><a href=\"#cb2-576\"></a> <span>Just</span> <span>$</span></span>\n<span><a href=\"#cb2-577\"></a> H.a <span>!</span> A.href (toValue <span>$</span> toUrl filePath) <span>$</span></span>\n<span><a href=\"#cb2-578\"></a> toHtml tag</span>\n<span><a href=\"#cb2-579\"></a></span>\n<span><a href=\"#cb2-580\"></a><span>isPublished ::</span> <span>Item</span> a <span>-&gt;</span> <span>Compiler</span> <span>Bool</span></span>\n<span><a href=\"#cb2-581\"></a>isPublished item <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-582\"></a> metadata <span>&lt;-</span> getMetadata (itemIdentifier item)</span>\n<span><a href=\"#cb2-583\"></a> <span>case</span> lookupString <span>&quot;published&quot;</span> metadata <span>of</span></span>\n<span><a href=\"#cb2-584\"></a> <span>Just</span> value <span>-&gt;</span> <span>return</span> (value <span>/=</span> <span>&quot;false&quot;</span>)</span>\n<span><a href=\"#cb2-585\"></a> <span>Nothing</span> <span>-&gt;</span> <span>return</span> (isJust (dateFromTitle item))</span>\n<span><a href=\"#cb2-586\"></a></span>\n<span><a href=\"#cb2-587\"></a><span>isNotDraft ::</span> <span>Item</span> a <span>-&gt;</span> <span>Compiler</span> <span>Bool</span></span>\n<span><a href=\"#cb2-588\"></a>isNotDraft item <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-589\"></a> metadata <span>&lt;-</span> getMetadata (itemIdentifier item)</span>\n<span><a href=\"#cb2-590\"></a> <span>return</span> <span>$</span> isNotDraftMeta metadata</span>\n<span><a href=\"#cb2-591\"></a></span>\n<span><a href=\"#cb2-592\"></a><span>isNotDraftMeta ::</span> <span>Metadata</span> <span>-&gt;</span> <span>Bool</span></span>\n<span><a href=\"#cb2-593\"></a>isNotDraftMeta metadata <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-594\"></a> <span>case</span> lookupString <span>&quot;published&quot;</span> metadata <span>of</span></span>\n<span><a href=\"#cb2-595\"></a> <span>Just</span> value <span>-&gt;</span> value <span>/=</span> <span>&quot;false&quot;</span></span>\n<span><a href=\"#cb2-596\"></a> <span>Nothing</span> <span>-&gt;</span> <span>True</span></span>\n<span><a href=\"#cb2-597\"></a></span>\n<span><a href=\"#cb2-598\"></a><span>dateFromTitle ::</span> <span>Item</span> a <span>-&gt;</span> <span>Maybe</span> <span>UTCTime</span></span>\n<span><a href=\"#cb2-599\"></a>dateFromTitle item <span>=</span></span>\n<span><a href=\"#cb2-600\"></a> <span>let</span> filePath <span>=</span> toFilePath (itemIdentifier item)</span>\n<span><a href=\"#cb2-601\"></a> title <span>=</span> takeBaseName filePath</span>\n<span><a href=\"#cb2-602\"></a> <span>in</span> parseTimeM <span>True</span> defaultTimeLocale <span>&quot;%Y-%m-%d&quot;</span> title</span>\n<span><a href=\"#cb2-603\"></a></span>\n<span><a href=\"#cb2-604\"></a><span>rewriteLinks ::</span> <span>String</span> <span>-&gt;</span> <span>String</span></span>\n<span><a href=\"#cb2-605\"></a>rewriteLinks url</span>\n<span><a href=\"#cb2-606\"></a> <span>|</span> <span>&quot;://&quot;</span> <span>`T.isInfixOf`</span> turl <span>=</span> url</span>\n<span><a href=\"#cb2-607\"></a> <span>-- workaround https://github.com/jgm/pandoc/issues/6916</span></span>\n<span><a href=\"#cb2-608\"></a> <span>|</span> <span>&quot;::&quot;</span> <span>`T.isInfixOf`</span> turl <span>=</span></span>\n<span><a href=\"#cb2-609\"></a> <span>let</span> (basePart, rest) <span>=</span> T.breakOn <span>&quot;::&quot;</span> turl</span>\n<span><a href=\"#cb2-610\"></a> cleanedBase <span>=</span> replaceExts basePart</span>\n<span><a href=\"#cb2-611\"></a> headingPart <span>=</span> T.drop <span>2</span> rest <span>-- Remove the &quot;::&quot;</span></span>\n<span><a href=\"#cb2-612\"></a> generatedId <span>=</span> generateId headingPart</span>\n<span><a href=\"#cb2-613\"></a> <span>in</span> T.unpack <span>$</span> cleanedBase <span>&lt;&gt;</span> <span>&quot;#&quot;</span> <span>&lt;&gt;</span> generatedId</span>\n<span><a href=\"#cb2-614\"></a> <span>|</span> <span>otherwise</span> <span>=</span></span>\n<span><a href=\"#cb2-615\"></a> <span>let</span> (base, fragment) <span>=</span> T.breakOn <span>&quot;#&quot;</span> turl</span>\n<span><a href=\"#cb2-616\"></a> processedBase <span>=</span> replaceExts base</span>\n<span><a href=\"#cb2-617\"></a> <span>in</span> T.unpack <span>$</span> processedBase <span>&lt;&gt;</span> fragment</span>\n<span><a href=\"#cb2-618\"></a> <span>where</span></span>\n<span><a href=\"#cb2-619\"></a> turl <span>=</span> T.pack url</span>\n<span><a href=\"#cb2-620\"></a> replaceExts <span>=</span> replaceExt <span>&quot;.md&quot;</span> <span>&quot;.html&quot;</span> <span>.</span> replaceExt <span>&quot;.org&quot;</span> <span>&quot;.html&quot;</span></span>\n<span><a href=\"#cb2-621\"></a></span>\n<span><a href=\"#cb2-622\"></a><span>replaceExt ::</span> <span>T.Text</span> <span>-&gt;</span> <span>T.Text</span> <span>-&gt;</span> <span>T.Text</span> <span>-&gt;</span> <span>T.Text</span></span>\n<span><a href=\"#cb2-623\"></a>replaceExt oldExt newExt url <span>=</span></span>\n<span><a href=\"#cb2-624\"></a> <span>let</span> (base, fragment) <span>=</span> T.breakOn <span>&quot;#&quot;</span> url</span>\n<span><a href=\"#cb2-625\"></a> cleanedBase <span>=</span> <span>if</span> <span>&quot;::&quot;</span> <span>`T.isSuffixOf`</span> base <span>then</span> T.dropEnd <span>2</span> base <span>else</span> base</span>\n<span><a href=\"#cb2-626\"></a> processedBase <span>=</span></span>\n<span><a href=\"#cb2-627\"></a> <span>if</span> oldExt <span>`T.isSuffixOf`</span> cleanedBase</span>\n<span><a href=\"#cb2-628\"></a> <span>then</span> T.replace oldExt newExt cleanedBase</span>\n<span><a href=\"#cb2-629\"></a> <span>else</span> cleanedBase</span>\n<span><a href=\"#cb2-630\"></a> <span>in</span> processedBase <span>&lt;&gt;</span> fragment</span>\n<span><a href=\"#cb2-631\"></a></span>\n<span><a href=\"#cb2-632\"></a><span>generateId ::</span> <span>T.Text</span> <span>-&gt;</span> <span>T.Text</span></span>\n<span><a href=\"#cb2-633\"></a>generateId heading <span>=</span></span>\n<span><a href=\"#cb2-634\"></a> <span>let</span> lower <span>=</span> T.toLower heading</span>\n<span><a href=\"#cb2-635\"></a> spaced <span>=</span> T.replace (T.pack <span>&quot; &quot;</span>) (T.pack <span>&quot;-&quot;</span>) lower</span>\n<span><a href=\"#cb2-636\"></a> filtered <span>=</span> T.filter (\\c <span>-&gt;</span> <span>isAlphaNum</span> c <span>||</span> c <span>==</span> <span>'-'</span> <span>||</span> c <span>==</span> <span>'_'</span> <span>||</span> c <span>==</span> <span>'.'</span>) spaced</span>\n<span><a href=\"#cb2-637\"></a> parts <span>=</span> T.split (<span>==</span> <span>'-'</span>) filtered</span>\n<span><a href=\"#cb2-638\"></a> nonEmptyParts <span>=</span> <span>filter</span> (<span>not</span> <span>.</span> T.null) parts</span>\n<span><a href=\"#cb2-639\"></a> cleaned <span>=</span> <span>if</span> <span>null</span> nonEmptyParts <span>then</span> T.pack <span>&quot;section&quot;</span> <span>else</span> T.intercalate (T.pack <span>&quot;-&quot;</span>) nonEmptyParts</span>\n<span><a href=\"#cb2-640\"></a> <span>in</span> cleaned</span>\n<span><a href=\"#cb2-641\"></a></span>\n<span><a href=\"#cb2-642\"></a><span>adjacentLogField ::</span> <span>Int</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Item</span> <span>String</span> <span>-&gt;</span> <span>Compiler</span> <span>String</span></span>\n<span><a href=\"#cb2-643\"></a>adjacentLogField offset format item <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-644\"></a> posts <span>&lt;-</span> loadAllSnapshots logFiles <span>&quot;body&quot;</span><span> ::</span> <span>Compiler</span> [<span>Item</span> <span>String</span>]</span>\n<span><a href=\"#cb2-645\"></a> <span>let</span> adjacent <span>=</span> getAdjacentLog posts item offset</span>\n<span><a href=\"#cb2-646\"></a> <span>case</span> adjacent <span>of</span></span>\n<span><a href=\"#cb2-647\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-648\"></a> <span>Just</span> a <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-649\"></a> mroute <span>&lt;-</span> getRoute (itemIdentifier a)</span>\n<span><a href=\"#cb2-650\"></a> <span>let</span> filePath <span>=</span> toFilePath (itemIdentifier item)</span>\n<span><a href=\"#cb2-651\"></a> title <span>=</span> takeBaseName filePath</span>\n<span><a href=\"#cb2-652\"></a> date <span>=</span> <span>fmap</span> (formatTime defaultTimeLocale format) (dateFromTitle a)</span>\n<span><a href=\"#cb2-653\"></a> label <span>=</span> fromMaybe title date</span>\n<span><a href=\"#cb2-654\"></a> <span>return</span> <span>$</span> <span>maybe</span> <span>&quot;&quot;</span> (\\r <span>-&gt;</span> <span>&quot;&lt;a href=\\&quot;&quot;</span> <span>++</span> r <span>++</span> <span>&quot;\\&quot;&gt;&quot;</span> <span>++</span> label <span>++</span> <span>&quot;&lt;/a&gt;&quot;</span>) mroute</span>\n<span><a href=\"#cb2-655\"></a></span>\n<span><a href=\"#cb2-656\"></a><span>getAdjacentLog ::</span> [<span>Item</span> a] <span>-&gt;</span> <span>Item</span> b <span>-&gt;</span> <span>Int</span> <span>-&gt;</span> <span>Maybe</span> (<span>Item</span> a)</span>\n<span><a href=\"#cb2-657\"></a>getAdjacentLog posts current offset <span>=</span></span>\n<span><a href=\"#cb2-658\"></a> <span>case</span> L.elemIndex (itemIdentifier current) (<span>map</span> itemIdentifier posts) <span>of</span></span>\n<span><a href=\"#cb2-659\"></a> <span>Nothing</span> <span>-&gt;</span> <span>Nothing</span></span>\n<span><a href=\"#cb2-660\"></a> <span>Just</span> idx <span>-&gt;</span></span>\n<span><a href=\"#cb2-661\"></a> <span>let</span> newIndex <span>=</span> idx <span>+</span> offset</span>\n<span><a href=\"#cb2-662\"></a> <span>in</span> <span>if</span> newIndex <span>&gt;=</span> <span>0</span> <span>&amp;&amp;</span> newIndex <span>&lt;</span> <span>length</span> posts</span>\n<span><a href=\"#cb2-663\"></a> <span>then</span> <span>Just</span> (posts <span>!!</span> newIndex)</span>\n<span><a href=\"#cb2-664\"></a> <span>else</span> <span>Nothing</span></span>\n<span><a href=\"#cb2-665\"></a></span>\n<span><a href=\"#cb2-666\"></a><span>titleCase ::</span> <span>String</span> <span>-&gt;</span> <span>String</span></span>\n<span><a href=\"#cb2-667\"></a>titleCase (x <span>:</span> xs) <span>=</span> C.toUpper x <span>:</span> <span>map</span> C.toLower xs</span>\n<span><a href=\"#cb2-668\"></a></span>\n<span><a href=\"#cb2-669\"></a><span>bibDate ::</span> <span>Bib</span> <span>-&gt;</span> <span>UTCTime</span></span>\n<span><a href=\"#cb2-670\"></a>bibDate b <span>=</span> <span>let</span></span>\n<span><a href=\"#cb2-671\"></a> latexifyPlain' <span>=</span> fromRight (<span>error</span> <span>$</span> <span>&quot;bibDate for entry &quot;</span> <span>&lt;&gt;</span> Bib.name b) <span>.</span> latexifyPlain</span>\n<span><a href=\"#cb2-672\"></a> date <span>=</span> latexifyPlain' <span>$</span> fromMaybe (<span>error</span> <span>$</span> <span>&quot;bibDate: no date in entry &quot;</span> <span>&lt;&gt;</span> Bib.name b) <span>$</span> bibIndex b <span>&quot;date&quot;</span></span>\n<span><a href=\"#cb2-673\"></a> parsed <span>=</span> parseTimeOrError <span>True</span> defaultTimeLocale <span>&quot;%Y-%m-%d&quot;</span><span> date ::</span> <span>UTCTime</span></span>\n<span><a href=\"#cb2-674\"></a> <span>in</span> parsed</span></code></pre></div>\n<p><span>The directory tree looks something like,</span></p>\n<pre><code>./ieee-with-url.csl\n./references.bib\n./scripts/anchor-links.lua\n./scripts/elem-ids.lua\n./scripts/footnote-commas.lua\n./static/about.org\n./static/articles.org\n./static/home.org\n./static/index.org\n./static/logs.org\n./static/news.org\n./static/papers.org\n./static/photos.org\n./static/research.org\n./static/keys\n./static/code.css\n./static/style.css\n./static/favicon.ico\n./static/rss.svg\n./static/2023-10-09.md\n./static/2023-10-16.md\n./static/2023-10-23.md\n./static/...\n./static/fonts/...\n./static/images/...\n./static/papers/...\n./static/photos/...\n./static/resources/...\n./templates/atom-item.xml\n./templates/atom.xml\n./templates/default.html\n./templates/log.html\n./templates/post-list.html\n./templates/post.html\n./templates/sitemap.xml\n./templates/tag.html\n</code></pre>\n<p><span>NB this is using <a href=\"https://gitlab.sac-home.org/tema/artem-blog/-/blob/master/BibHakyll.hs\">BibHakyll.hs</a>\nand <a href=\"https://gitlab.sac-home.org/tema/artem-blog/-/blob/master/Bib.hs\">Bib.hs</a>.</span></p>", 8 "content": "<div>\n \n <span>Published 26 Mar 2025.</span>\n \n \n <span>Last update 16 Jul 2025.</span>\n \n </div>\n \n \n\n <p><span>This site has continuously evolved since I made the\nfirst commit while procrastinating my undergrad dissertation,</span></p>\n<div><pre><code><span><a href=\"#cb1-1\"></a>commit 632cb1f0c97c07fb99b48192444397e56ea5310f</span>\n<span><a href=\"#cb1-2\"></a>Author: Ryan Gibb &lt;redacted&gt;</span>\n<span><a href=\"#cb1-3\"></a>Date: Fri Jan 22 11:27:55 2021 +0000</span>\n<span><a href=\"#cb1-4\"></a></span>\n<span><a href=\"#cb1-5\"></a> Initial commit</span>\n<span><a href=\"#cb1-6\"></a></span>\n<span><a href=\"#cb1-7\"></a><span>diff --git a/index.html b/index.html</span></span>\n<span><a href=\"#cb1-8\"></a>new file mode 100644</span>\n<span><a href=\"#cb1-9\"></a>index 0000000..557db03</span>\n<span><a href=\"#cb1-10\"></a><span>--- /dev/null</span></span>\n<span><a href=\"#cb1-11\"></a><span>+++ b/index.html</span></span>\n<span><a href=\"#cb1-12\"></a><span>@@ -0,0 +1 @@</span></span>\n<span><a href=\"#cb1-13\"></a><span>+Hello World</span></span></code></pre></div>\n<p><span>I started off writing plain HTML, then switching to\nwriting in markdown and using <a href=\"https://pandoc.org/\">pandoc</a>\nto convert to HTML, and gradually accumulated bash scripts and makefiles\nto add more functionality, such as generating an <a href=\"https://www.rfc-editor.org/rfc/rfc4287\">Atom feed</a>. This became\nunmaintainable and at the start of 2025 I overhauled it to use the <a href=\"https://jaspervdj.be/hakyll/\">Hakyll</a> static site generator\nThere’s a few drafts in the git repository which I don’t want to make\npublic yet, so I include the source code used to generate this website\nbelow. It’s quite particular to my needs – Hakyll give you a big bag of\ntools which you can compose in your own way – but it may be useful as a\nreference.</span></p>\n<div><pre><code><span><a href=\"#cb2-1\"></a><span>{-# LANGUAGE OverloadedStrings #-}</span></span>\n<span><a href=\"#cb2-2\"></a><span>{-# LANGUAGE ScopedTypeVariables #-}</span></span>\n<span><a href=\"#cb2-3\"></a></span>\n<span><a href=\"#cb2-4\"></a><span>import</span> <span>Bib</span></span>\n<span><a href=\"#cb2-5\"></a><span>import</span> <span>BibHakyll</span></span>\n<span><a href=\"#cb2-6\"></a></span>\n<span><a href=\"#cb2-7\"></a><span>import</span> <span>Control.Applicative</span> ((&lt;|&gt;))</span>\n<span><a href=\"#cb2-8\"></a><span>import</span> <span>Control.Monad</span> (filterM, forM, liftM, (&gt;=&gt;), forM_)</span>\n<span><a href=\"#cb2-9\"></a><span>import</span> <span>Control.Monad.IO.Class</span> (liftIO)</span>\n<span><a href=\"#cb2-10\"></a><span>import</span> <span>Data.Aeson</span></span>\n<span><a href=\"#cb2-11\"></a><span>import</span> <span>Data.Aeson.Types</span> (<span>Parser</span>)</span>\n<span><a href=\"#cb2-12\"></a><span>import</span> <span>qualified</span> <span>Data.ByteString.Lazy</span> <span>as</span> <span>BSL</span></span>\n<span><a href=\"#cb2-13\"></a><span>import</span> <span>Data.Char</span> (isAlphaNum)</span>\n<span><a href=\"#cb2-14\"></a><span>import</span> <span>qualified</span> <span>Data.Char</span> <span>as</span> <span>C</span></span>\n<span><a href=\"#cb2-15\"></a><span>import</span> <span>Data.Either</span> (fromRight)</span>\n<span><a href=\"#cb2-16\"></a><span>import</span> <span>qualified</span> <span>Data.HashMap.Strict</span> <span>as</span> <span>HM</span></span>\n<span><a href=\"#cb2-17\"></a><span>import</span> <span>qualified</span> <span>Data.List</span> <span>as</span> <span>L</span></span>\n<span><a href=\"#cb2-18\"></a><span>import</span> <span>qualified</span> <span>Data.Map</span> <span>as</span> <span>M</span></span>\n<span><a href=\"#cb2-19\"></a><span>import</span> <span>Data.Maybe</span> (catMaybes, fromMaybe, isJust, listToMaybe, mapMaybe)</span>\n<span><a href=\"#cb2-20\"></a><span>import</span> <span>Data.Monoid</span> (mappend)</span>\n<span><a href=\"#cb2-21\"></a><span>import</span> <span>Data.Text</span> (<span>Text</span>, intercalate, isInfixOf, pack, unpack)</span>\n<span><a href=\"#cb2-22\"></a><span>import</span> <span>qualified</span> <span>Data.Text</span> <span>as</span> <span>T</span></span>\n<span><a href=\"#cb2-23\"></a><span>import</span> <span>Data.Time</span> (<span>UTCTime</span> (<span>UTCTime</span>))</span>\n<span><a href=\"#cb2-24\"></a><span>import</span> <span>Data.Time.Format</span> (formatTime, parseTimeM)</span>\n<span><a href=\"#cb2-25\"></a><span>import</span> <span>Data.Time.Locale.Compat</span> (defaultTimeLocale)</span>\n<span><a href=\"#cb2-26\"></a><span>import</span> <span>Graphics.HsExif</span></span>\n<span><a href=\"#cb2-27\"></a><span>import</span> <span>Hakyll</span></span>\n<span><a href=\"#cb2-28\"></a><span>import</span> <span>Numeric</span> (showFFloat)</span>\n<span><a href=\"#cb2-29\"></a><span>import</span> <span>System.Directory</span> (doesFileExist)</span>\n<span><a href=\"#cb2-30\"></a><span>import</span> <span>System.FilePath</span> (takeBaseName, takeFileName)</span>\n<span><a href=\"#cb2-31\"></a><span>import</span> <span>Text.Blaze.Html</span> (toHtml, toValue, (!))</span>\n<span><a href=\"#cb2-32\"></a><span>import</span> <span>qualified</span> <span>Text.Blaze.Html</span> <span>as</span> <span>ExifTag</span></span>\n<span><a href=\"#cb2-33\"></a><span>import</span> <span>Text.Blaze.Html.Renderer.String</span> (renderHtml)</span>\n<span><a href=\"#cb2-34\"></a><span>import</span> <span>qualified</span> <span>Text.Blaze.Html5</span> <span>as</span> <span>H</span></span>\n<span><a href=\"#cb2-35\"></a><span>import</span> <span>qualified</span> <span>Text.Blaze.Html5.Attributes</span> <span>as</span> <span>A</span></span>\n<span><a href=\"#cb2-36\"></a><span>import</span> <span>Text.Pandoc</span></span>\n<span><a href=\"#cb2-37\"></a><span>import</span> <span>Text.Pandoc.Highlighting</span> (pygments)</span>\n<span><a href=\"#cb2-38\"></a><span>import</span> <span>Text.Pandoc.Lua</span> (applyFilter)</span>\n<span><a href=\"#cb2-39\"></a><span>import</span> <span>Data.Ord</span> (comparing)</span>\n<span><a href=\"#cb2-40\"></a><span>import</span> <span>Data.Time</span> (<span>UTCTime</span>(<span>UTCTime</span>), parseTimeOrError, defaultTimeLocale) <span>--, parseTimeM, parseTime)</span></span>\n<span><a href=\"#cb2-41\"></a></span>\n<span><a href=\"#cb2-42\"></a>indexFiles <span>=</span></span>\n<span><a href=\"#cb2-43\"></a> <span>&quot;static/home.org&quot;</span></span>\n<span><a href=\"#cb2-44\"></a> <span>.||.</span> <span>&quot;static/logs.org&quot;</span></span>\n<span><a href=\"#cb2-45\"></a> <span>.||.</span> <span>&quot;static/news.org&quot;</span></span>\n<span><a href=\"#cb2-46\"></a> <span>.||.</span> <span>&quot;static/index.org&quot;</span></span>\n<span><a href=\"#cb2-47\"></a> <span>.||.</span> <span>&quot;static/photos.org&quot;</span></span>\n<span><a href=\"#cb2-48\"></a> <span>.||.</span> <span>&quot;static/papers.org&quot;</span></span>\n<span><a href=\"#cb2-49\"></a></span>\n<span><a href=\"#cb2-50\"></a>tagFiles <span>=</span></span>\n<span><a href=\"#cb2-51\"></a> <span>&quot;static/projects.org&quot;</span></span>\n<span><a href=\"#cb2-52\"></a> <span>.||.</span> <span>&quot;static/research.org&quot;</span></span>\n<span><a href=\"#cb2-53\"></a> <span>.||.</span> <span>&quot;static/technology.org&quot;</span></span>\n<span><a href=\"#cb2-54\"></a> <span>.||.</span> <span>&quot;static/self-hosting.org&quot;</span></span>\n<span><a href=\"#cb2-55\"></a></span>\n<span><a href=\"#cb2-56\"></a>htmlFiles <span>=</span> <span>&quot;static/**.md&quot;</span> <span>.||.</span> <span>&quot;static/**.org&quot;</span></span>\n<span><a href=\"#cb2-57\"></a></span>\n<span><a href=\"#cb2-58\"></a>postFiles <span>=</span> htmlFiles <span>.&amp;&amp;.</span> complement indexFiles <span>.&amp;&amp;.</span> complement tagFiles</span>\n<span><a href=\"#cb2-59\"></a></span>\n<span><a href=\"#cb2-60\"></a>photoFiles <span>=</span> <span>&quot;static/photos/*&quot;</span></span>\n<span><a href=\"#cb2-61\"></a></span>\n<span><a href=\"#cb2-62\"></a>logFiles <span>=</span> fromRegex <span>&quot;static/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].*&quot;</span></span>\n<span><a href=\"#cb2-63\"></a></span>\n<span><a href=\"#cb2-64\"></a>articleFiles <span>=</span> postFiles <span>.&amp;&amp;.</span> complement logFiles</span>\n<span><a href=\"#cb2-65\"></a></span>\n<span><a href=\"#cb2-66\"></a><span>dateFormat ::</span> <span>String</span></span>\n<span><a href=\"#cb2-67\"></a>dateFormat <span>=</span> <span>&quot;%e %b %Y&quot;</span></span>\n<span><a href=\"#cb2-68\"></a></span>\n<span><a href=\"#cb2-69\"></a><span>feedConfiguration ::</span> <span>FeedConfiguration</span></span>\n<span><a href=\"#cb2-70\"></a>feedConfiguration <span>=</span></span>\n<span><a href=\"#cb2-71\"></a> <span>FeedConfiguration</span></span>\n<span><a href=\"#cb2-72\"></a> { feedTitle <span>=</span> <span>&quot;ryan.freumh.org&quot;</span>,</span>\n<span><a href=\"#cb2-73\"></a> feedDescription <span>=</span> <span>&quot;ryan.freumh.org&quot;</span>,</span>\n<span><a href=\"#cb2-74\"></a> feedAuthorName <span>=</span> <span>&quot;Ryan Gibb&quot;</span>,</span>\n<span><a href=\"#cb2-75\"></a> feedAuthorEmail <span>=</span> <span>&quot;ryan@freumh.org&quot;</span>,</span>\n<span><a href=\"#cb2-76\"></a> feedRoot <span>=</span> <span>&quot;https://ryan.freumh.org&quot;</span></span>\n<span><a href=\"#cb2-77\"></a> }</span>\n<span><a href=\"#cb2-78\"></a></span>\n<span><a href=\"#cb2-79\"></a><span>main ::</span> <span>IO</span> ()</span>\n<span><a href=\"#cb2-80\"></a>main <span>=</span> hakyll <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-81\"></a> tags <span>&lt;-</span> buildTags postFiles (fromCapture <span>&quot;*.html&quot;</span>)</span>\n<span><a href=\"#cb2-82\"></a></span>\n<span><a href=\"#cb2-83\"></a> match tagFiles <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-84\"></a> route idRoute</span>\n<span><a href=\"#cb2-85\"></a> compile tagCompiler</span>\n<span><a href=\"#cb2-86\"></a></span>\n<span><a href=\"#cb2-87\"></a> tagsRules tags <span>$</span> \\tag <span>pattern</span> <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-88\"></a> route idRoute</span>\n<span><a href=\"#cb2-89\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-90\"></a> <span>let</span> title <span>=</span> titleCase tag</span>\n<span><a href=\"#cb2-91\"></a> <span>let</span> file <span>=</span> <span>&quot;static/&quot;</span> <span>++</span> tag <span>++</span> <span>&quot;.org&quot;</span></span>\n<span><a href=\"#cb2-92\"></a> posts <span>&lt;-</span> recentFirst <span>=&lt;&lt;</span> filterM isPublished <span>=&lt;&lt;</span> loadAll <span>pattern</span></span>\n<span><a href=\"#cb2-93\"></a> <span>let</span> ctx <span>=</span></span>\n<span><a href=\"#cb2-94\"></a> constField <span>&quot;title&quot;</span> title</span>\n<span><a href=\"#cb2-95\"></a> <span>`mappend`</span> listField <span>&quot;posts&quot;</span> (postContext dateFormat dateFormat tags) (<span>return</span> posts)</span>\n<span><a href=\"#cb2-96\"></a> <span>`mappend`</span> defaultContext</span>\n<span><a href=\"#cb2-97\"></a> exists <span>&lt;-</span> unsafeCompiler <span>$</span> doesFileExist file</span>\n<span><a href=\"#cb2-98\"></a> <span>if</span> exists</span>\n<span><a href=\"#cb2-99\"></a> <span>then</span> <span>do</span></span>\n<span><a href=\"#cb2-100\"></a> body <span>&lt;-</span> load <span>$</span> fromFilePath file</span>\n<span><a href=\"#cb2-101\"></a> makeItem (itemBody body)</span>\n<span><a href=\"#cb2-102\"></a> <span>&gt;&gt;=</span> applyAsTemplate (indexContext posts (postContext dateFormat dateFormat tags))</span>\n<span><a href=\"#cb2-103\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> ctx</span>\n<span><a href=\"#cb2-104\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-105\"></a> <span>else</span></span>\n<span><a href=\"#cb2-106\"></a> makeItem <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-107\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/tag.html&quot;</span> ctx</span>\n<span><a href=\"#cb2-108\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> ctx</span>\n<span><a href=\"#cb2-109\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-110\"></a></span>\n<span><a href=\"#cb2-111\"></a> match <span>&quot;static/home.org&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-112\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-113\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-114\"></a> posts <span>&lt;-</span> recentFirst <span>=&lt;&lt;</span> filterM isPublished <span>=&lt;&lt;</span> loadAll articleFiles</span>\n<span><a href=\"#cb2-115\"></a> indexCompiler posts (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-116\"></a></span>\n<span><a href=\"#cb2-117\"></a> match <span>&quot;static/logs.org&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-118\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-119\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-120\"></a> <span>-- so that we pick up published from the title in postContext</span></span>\n<span><a href=\"#cb2-121\"></a> posts <span>&lt;-</span> <span>reverse</span> <span>&lt;$&gt;</span> loadAllSnapshots logFiles <span>&quot;feed&quot;</span></span>\n<span><a href=\"#cb2-122\"></a> indexCompiler posts (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-123\"></a></span>\n<span><a href=\"#cb2-124\"></a> match <span>&quot;static/news.org&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-125\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-126\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-127\"></a> posts <span>&lt;-</span> recentFirst <span>=&lt;&lt;</span> filterM isPublished <span>=&lt;&lt;</span> loadAll postFiles</span>\n<span><a href=\"#cb2-128\"></a> indexCompiler posts (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-129\"></a></span>\n<span><a href=\"#cb2-130\"></a> match <span>&quot;static/index.org&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-131\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-132\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-133\"></a> posts <span>&lt;-</span> filterM isNotDraft <span>=&lt;&lt;</span> loadAll (htmlFiles <span>.&amp;&amp;.</span> complement <span>&quot;static/index.org&quot;</span>)</span>\n<span><a href=\"#cb2-134\"></a> indexCompiler posts (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-135\"></a></span>\n<span><a href=\"#cb2-136\"></a> match <span>&quot;static/photos.org&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-137\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-138\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-139\"></a> photos <span>&lt;-</span> recentFirst <span>=&lt;&lt;</span> (loadAll (photoFiles <span>.&amp;&amp;.</span> hasNoVersion)<span> ::</span> <span>Compiler</span> [<span>Item</span> <span>CopyFile</span>])</span>\n<span><a href=\"#cb2-140\"></a> photosCompiler photos</span>\n<span><a href=\"#cb2-141\"></a></span>\n<span><a href=\"#cb2-142\"></a> match <span>&quot;papers.bib&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-143\"></a> route idRoute</span>\n<span><a href=\"#cb2-144\"></a> compile bibFileCompiler</span>\n<span><a href=\"#cb2-145\"></a></span>\n<span><a href=\"#cb2-146\"></a> match <span>&quot;static/papers.org&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-147\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-148\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-149\"></a> (<span>Bibs</span> bibFile) <span>&lt;-</span> loadBody <span>&quot;papers.bib&quot;</span><span> ::</span> <span>Compiler</span> <span>Bibs</span></span>\n<span><a href=\"#cb2-150\"></a> <span>let</span> sortedBibs <span>=</span> <span>reverse</span> <span>$</span> <span>fmap</span> <span>fst</span> <span>$</span> L.sortBy (comparing <span>snd</span>) <span>$</span> <span>fmap</span> (\\b <span>-&gt;</span> (b, bibDate b)) bibFile</span>\n<span><a href=\"#cb2-151\"></a> <span>let</span> bibsCtx <span>=</span> listField <span>&quot;papers&quot;</span> (bibContext dateFormat) (<span>mapM</span> makeItem sortedBibs)</span>\n<span><a href=\"#cb2-152\"></a> getResourceBody</span>\n<span><a href=\"#cb2-153\"></a> <span>&gt;&gt;=</span> renderPandoc</span>\n<span><a href=\"#cb2-154\"></a> <span>&gt;&gt;=</span> applyAsTemplate bibsCtx</span>\n<span><a href=\"#cb2-155\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> defaultContext</span>\n<span><a href=\"#cb2-156\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-157\"></a></span>\n<span><a href=\"#cb2-158\"></a> (<span>Bibs</span> bibs) <span>&lt;-</span> preprocess <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-159\"></a> parseBibFile <span>&lt;$&gt;</span> <span>readFile</span> <span>&quot;papers.bib&quot;</span></span>\n<span><a href=\"#cb2-160\"></a></span>\n<span><a href=\"#cb2-161\"></a> forM_ bibs <span>$</span> \\b <span>-&gt;</span></span>\n<span><a href=\"#cb2-162\"></a> create [fromCapture <span>&quot;papers/*.bib&quot;</span> <span>$</span> name b] <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-163\"></a> route idRoute</span>\n<span><a href=\"#cb2-164\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-165\"></a> bibFile <span>&lt;-</span> loadBody <span>&quot;papers.bib&quot;</span><span> ::</span> <span>Compiler</span> <span>Bibs</span></span>\n<span><a href=\"#cb2-166\"></a> makeItem b</span>\n<span><a href=\"#cb2-167\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/bib&quot;</span> (bibContext dateFormat)</span>\n<span><a href=\"#cb2-168\"></a></span>\n<span><a href=\"#cb2-169\"></a> matchMetadata articleFiles isNotDraftMeta <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-170\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-171\"></a> compile <span>$</span> postCompiler tags <span>&quot;templates/post.html&quot;</span></span>\n<span><a href=\"#cb2-172\"></a></span>\n<span><a href=\"#cb2-173\"></a> matchMetadata logFiles isNotDraftMeta <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-174\"></a> route <span>$</span> staticRoute <span>`composeRoutes`</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-175\"></a> compile <span>$</span> postCompiler tags <span>&quot;templates/log.html&quot;</span></span>\n<span><a href=\"#cb2-176\"></a></span>\n<span><a href=\"#cb2-177\"></a> create [<span>&quot;atom.xml&quot;</span>] <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-178\"></a> route idRoute</span>\n<span><a href=\"#cb2-179\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-180\"></a> <span>let</span> feedContext <span>=</span> postContext dateFormat <span>&quot;%Y-%m-%dT%H:%M:%S%Q%Ez&quot;</span> tags <span>`mappend`</span> bodyField <span>&quot;content&quot;</span></span>\n<span><a href=\"#cb2-181\"></a> posts <span>&lt;-</span> recentFirst <span>=&lt;&lt;</span> filterM isPublished <span>=&lt;&lt;</span> loadAllSnapshots postFiles <span>&quot;feed&quot;</span></span>\n<span><a href=\"#cb2-182\"></a> atomTemplate <span>&lt;-</span> loadBody <span>&quot;templates/atom.xml&quot;</span></span>\n<span><a href=\"#cb2-183\"></a> atomItemTemplate <span>&lt;-</span> loadBody <span>&quot;templates/atom-item.xml&quot;</span></span>\n<span><a href=\"#cb2-184\"></a> renderAtomWithTemplates atomTemplate atomItemTemplate feedConfiguration feedContext posts</span>\n<span><a href=\"#cb2-185\"></a></span>\n<span><a href=\"#cb2-186\"></a> create [<span>&quot;sitemap.xml&quot;</span>] <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-187\"></a> route idRoute</span>\n<span><a href=\"#cb2-188\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-189\"></a> posts <span>&lt;-</span> loadAll htmlFiles</span>\n<span><a href=\"#cb2-190\"></a> <span>let</span> sitemapCtx <span>=</span></span>\n<span><a href=\"#cb2-191\"></a> listField <span>&quot;posts&quot;</span> (urlField <span>&quot;loc&quot;</span> <span>`mappend`</span> postContext dateFormat dateFormat tags) (<span>return</span> posts)</span>\n<span><a href=\"#cb2-192\"></a> <span>`mappend`</span> constField <span>&quot;root&quot;</span> <span>&quot;https://ryan.freumh.org&quot;</span></span>\n<span><a href=\"#cb2-193\"></a> <span>`mappend`</span> defaultContext</span>\n<span><a href=\"#cb2-194\"></a> makeItem <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-195\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/sitemap.xml&quot;</span> sitemapCtx</span>\n<span><a href=\"#cb2-196\"></a></span>\n<span><a href=\"#cb2-197\"></a> match <span>&quot;404.md&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-198\"></a> route <span>$</span> setExtension <span>&quot;html&quot;</span></span>\n<span><a href=\"#cb2-199\"></a> compile <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-200\"></a> getResourceBody</span>\n<span><a href=\"#cb2-201\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> defaultContext</span>\n<span><a href=\"#cb2-202\"></a></span>\n<span><a href=\"#cb2-203\"></a> matchMetadata <span>&quot;static/**&quot;</span> isNotDraftMeta <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-204\"></a> route staticRoute</span>\n<span><a href=\"#cb2-205\"></a> compile copyFileCompiler</span>\n<span><a href=\"#cb2-206\"></a></span>\n<span><a href=\"#cb2-207\"></a> match <span>&quot;static/*.css&quot;</span> <span>$</span> <span>do</span></span>\n<span><a href=\"#cb2-208\"></a> route staticRoute</span>\n<span><a href=\"#cb2-209\"></a> compile compressCssCompiler</span>\n<span><a href=\"#cb2-210\"></a></span>\n<span><a href=\"#cb2-211\"></a> match <span>&quot;ieee-with-url.csl&quot;</span> <span>$</span></span>\n<span><a href=\"#cb2-212\"></a> compile cslCompiler</span>\n<span><a href=\"#cb2-213\"></a></span>\n<span><a href=\"#cb2-214\"></a> match <span>&quot;references.bib&quot;</span> <span>$</span></span>\n<span><a href=\"#cb2-215\"></a> compile biblioCompiler</span>\n<span><a href=\"#cb2-216\"></a></span>\n<span><a href=\"#cb2-217\"></a> match <span>&quot;templates/*&quot;</span> <span>$</span></span>\n<span><a href=\"#cb2-218\"></a> compile templateBodyCompiler</span>\n<span><a href=\"#cb2-219\"></a></span>\n<span><a href=\"#cb2-220\"></a><span>staticRoute ::</span> <span>Routes</span></span>\n<span><a href=\"#cb2-221\"></a>staticRoute <span>=</span> gsubRoute <span>&quot;static/&quot;</span> (<span>const</span> <span>&quot;&quot;</span>)</span>\n<span><a href=\"#cb2-222\"></a></span>\n<span><a href=\"#cb2-223\"></a><span>indexCompiler ::</span> [<span>Item</span> a] <span>-&gt;</span> <span>Context</span> a <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-224\"></a>indexCompiler posts context <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-225\"></a> getResourceBody</span>\n<span><a href=\"#cb2-226\"></a> <span>&gt;&gt;=</span> transformRender</span>\n<span><a href=\"#cb2-227\"></a> <span>&gt;&gt;=</span> applyAsTemplate (indexContext posts context)</span>\n<span><a href=\"#cb2-228\"></a> <span>&gt;&gt;=</span> linkCompiler</span>\n<span><a href=\"#cb2-229\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> defaultContext</span>\n<span><a href=\"#cb2-230\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-231\"></a></span>\n<span><a href=\"#cb2-232\"></a><span>tagCompiler ::</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-233\"></a>tagCompiler <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-234\"></a> getResourceBody</span>\n<span><a href=\"#cb2-235\"></a> <span>&gt;&gt;=</span> bibRender <span>&quot;ieee-with-url.csl&quot;</span> <span>&quot;references.bib&quot;</span></span>\n<span><a href=\"#cb2-236\"></a> <span>&gt;&gt;=</span> linkCompiler</span>\n<span><a href=\"#cb2-237\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-238\"></a></span>\n<span><a href=\"#cb2-239\"></a><span>postCompiler ::</span> <span>Tags</span> <span>-&gt;</span> <span>Identifier</span> <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-240\"></a>postCompiler tags template <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-241\"></a> getResourceBody</span>\n<span><a href=\"#cb2-242\"></a> <span>&gt;&gt;=</span> saveSnapshot <span>&quot;body&quot;</span></span>\n<span><a href=\"#cb2-243\"></a> <span>&gt;&gt;=</span> bibRenderFeed <span>&quot;ieee-with-url.csl&quot;</span> <span>&quot;references.bib&quot;</span></span>\n<span><a href=\"#cb2-244\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate template (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-245\"></a> <span>&gt;&gt;=</span> linkCompiler</span>\n<span><a href=\"#cb2-246\"></a> <span>&gt;&gt;=</span> saveSnapshot <span>&quot;feed&quot;</span></span>\n<span><a href=\"#cb2-247\"></a> getResourceBody</span>\n<span><a href=\"#cb2-248\"></a> <span>&gt;&gt;=</span> saveSnapshot <span>&quot;body&quot;</span></span>\n<span><a href=\"#cb2-249\"></a> <span>&gt;&gt;=</span> bibRender <span>&quot;ieee-with-url.csl&quot;</span> <span>&quot;references.bib&quot;</span></span>\n<span><a href=\"#cb2-250\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate template (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-251\"></a> <span>&gt;&gt;=</span> linkCompiler</span>\n<span><a href=\"#cb2-252\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> (postContext dateFormat dateFormat tags)</span>\n<span><a href=\"#cb2-253\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-254\"></a></span>\n<span><a href=\"#cb2-255\"></a><span>linkCompiler ::</span> <span>Item</span> <span>String</span> <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-256\"></a>linkCompiler <span>=</span> <span>pure</span> <span>.</span> <span>fmap</span> (withUrls rewriteLinks)</span>\n<span><a href=\"#cb2-257\"></a></span>\n<span><a href=\"#cb2-258\"></a><span>photosCompiler ::</span> [<span>Item</span> a] <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-259\"></a>photosCompiler photos <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-260\"></a> getResourceBody</span>\n<span><a href=\"#cb2-261\"></a> <span>&gt;&gt;=</span> renderPandoc</span>\n<span><a href=\"#cb2-262\"></a> <span>&gt;&gt;=</span> applyAsTemplate (photosContext photos)</span>\n<span><a href=\"#cb2-263\"></a> <span>&gt;&gt;=</span> loadAndApplyTemplate <span>&quot;templates/default.html&quot;</span> defaultContext</span>\n<span><a href=\"#cb2-264\"></a> <span>&gt;&gt;=</span> relativizeUrls</span>\n<span><a href=\"#cb2-265\"></a></span>\n<span><a href=\"#cb2-266\"></a><span>readerOptions ::</span> <span>ReaderOptions</span></span>\n<span><a href=\"#cb2-267\"></a>readerOptions <span>=</span></span>\n<span><a href=\"#cb2-268\"></a> def</span>\n<span><a href=\"#cb2-269\"></a> { readerExtensions <span>=</span> <span>foldr</span> enableExtension pandocExtensions [<span>Ext_citations</span>, <span>Ext_smart</span>]</span>\n<span><a href=\"#cb2-270\"></a> }</span>\n<span><a href=\"#cb2-271\"></a></span>\n<span><a href=\"#cb2-272\"></a><span>writerOptions ::</span> <span>WriterOptions</span></span>\n<span><a href=\"#cb2-273\"></a>writerOptions <span>=</span></span>\n<span><a href=\"#cb2-274\"></a> def</span>\n<span><a href=\"#cb2-275\"></a> { writerExtensions <span>=</span> enableExtension <span>Ext_smart</span> pandocExtensions,</span>\n<span><a href=\"#cb2-276\"></a> writerHighlightStyle <span>=</span> <span>Just</span> pygments,</span>\n<span><a href=\"#cb2-277\"></a> writerCiteMethod <span>=</span> <span>Citeproc</span></span>\n<span><a href=\"#cb2-278\"></a> }</span>\n<span><a href=\"#cb2-279\"></a></span>\n<span><a href=\"#cb2-280\"></a><span>transformRender ::</span> <span>Item</span> <span>String</span> <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-281\"></a>transformRender <span>=</span></span>\n<span><a href=\"#cb2-282\"></a> renderPandocWithTransformM defaultHakyllReaderOptions defaultHakyllWriterOptions pandocTransform</span>\n<span><a href=\"#cb2-283\"></a></span>\n<span><a href=\"#cb2-284\"></a><span>bibRender ::</span> <span>String</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Item</span> <span>String</span> <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-285\"></a>bibRender cslFileName bibFileName pandoc <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-286\"></a> csl <span>&lt;-</span> load <span>$</span> fromFilePath cslFileName</span>\n<span><a href=\"#cb2-287\"></a> bib <span>&lt;-</span> load <span>$</span> fromFilePath bibFileName</span>\n<span><a href=\"#cb2-288\"></a> <span>let</span> transform <span>=</span></span>\n<span><a href=\"#cb2-289\"></a> withItemBody</span>\n<span><a href=\"#cb2-290\"></a> ( \\(<span>Pandoc</span> (<span>Meta</span> meta) bs) <span>-&gt;</span></span>\n<span><a href=\"#cb2-291\"></a> <span>pure</span> <span>$</span></span>\n<span><a href=\"#cb2-292\"></a> <span>Pandoc</span></span>\n<span><a href=\"#cb2-293\"></a> (<span>Meta</span> <span>$</span> M.insert <span>&quot;link-citations&quot;</span> (<span>MetaBool</span> <span>True</span>) meta)</span>\n<span><a href=\"#cb2-294\"></a> bs</span>\n<span><a href=\"#cb2-295\"></a> )</span>\n<span><a href=\"#cb2-296\"></a> <span>&gt;=&gt;</span> processPandocBiblios csl [bib]</span>\n<span><a href=\"#cb2-297\"></a> <span>&gt;=&gt;</span> withItemBody pandocTransform</span>\n<span><a href=\"#cb2-298\"></a> renderPandocItemWithTransformM readerOptions writerOptions transform pandoc</span>\n<span><a href=\"#cb2-299\"></a></span>\n<span><a href=\"#cb2-300\"></a><span>bibRenderFeed ::</span> <span>String</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Item</span> <span>String</span> <span>-&gt;</span> <span>Compiler</span> (<span>Item</span> <span>String</span>)</span>\n<span><a href=\"#cb2-301\"></a>bibRenderFeed cslFileName bibFileName pandoc <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-302\"></a> csl <span>&lt;-</span> load <span>$</span> fromFilePath cslFileName</span>\n<span><a href=\"#cb2-303\"></a> bib <span>&lt;-</span> load <span>$</span> fromFilePath bibFileName</span>\n<span><a href=\"#cb2-304\"></a> <span>let</span> transform <span>=</span></span>\n<span><a href=\"#cb2-305\"></a> withItemBody</span>\n<span><a href=\"#cb2-306\"></a> ( \\(<span>Pandoc</span> (<span>Meta</span> meta) bs) <span>-&gt;</span></span>\n<span><a href=\"#cb2-307\"></a> <span>pure</span> <span>$</span></span>\n<span><a href=\"#cb2-308\"></a> <span>Pandoc</span></span>\n<span><a href=\"#cb2-309\"></a> (<span>Meta</span> <span>$</span> M.insert <span>&quot;link-citations&quot;</span> (<span>MetaBool</span> <span>True</span>) meta)</span>\n<span><a href=\"#cb2-310\"></a> bs</span>\n<span><a href=\"#cb2-311\"></a> )</span>\n<span><a href=\"#cb2-312\"></a> <span>&gt;=&gt;</span> processPandocBiblios csl [bib]</span>\n<span><a href=\"#cb2-313\"></a> <span>&gt;=&gt;</span> withItemBody pandocTransformFeed</span>\n<span><a href=\"#cb2-314\"></a> renderPandocItemWithTransformM readerOptions writerOptions transform pandoc</span>\n<span><a href=\"#cb2-315\"></a></span>\n<span><a href=\"#cb2-316\"></a><span>pandocTransform ::</span> <span>Pandoc</span> <span>-&gt;</span> <span>Compiler</span> <span>Pandoc</span></span>\n<span><a href=\"#cb2-317\"></a>pandocTransform <span>=</span></span>\n<span><a href=\"#cb2-318\"></a> unsafeCompiler</span>\n<span><a href=\"#cb2-319\"></a> <span>.</span> runIOorExplode</span>\n<span><a href=\"#cb2-320\"></a> <span>.</span> ( applyFilter def [] <span>&quot;scripts/org-keywords.lua&quot;</span></span>\n<span><a href=\"#cb2-321\"></a> <span>&gt;=&gt;</span> applyFilter def [] <span>&quot;scripts/elem-ids.lua&quot;</span></span>\n<span><a href=\"#cb2-322\"></a> <span>&gt;=&gt;</span> applyFilter def [] <span>&quot;scripts/footnote-commas.lua&quot;</span></span>\n<span><a href=\"#cb2-323\"></a> <span>&gt;=&gt;</span> applyFilter def [] <span>&quot;scripts/anchor-links.lua&quot;</span></span>\n<span><a href=\"#cb2-324\"></a> )</span>\n<span><a href=\"#cb2-325\"></a></span>\n<span><a href=\"#cb2-326\"></a><span>pandocTransformFeed ::</span> <span>Pandoc</span> <span>-&gt;</span> <span>Compiler</span> <span>Pandoc</span></span>\n<span><a href=\"#cb2-327\"></a>pandocTransformFeed <span>=</span></span>\n<span><a href=\"#cb2-328\"></a> unsafeCompiler</span>\n<span><a href=\"#cb2-329\"></a> <span>.</span> runIOorExplode</span>\n<span><a href=\"#cb2-330\"></a> <span>.</span> ( applyFilter def [] <span>&quot;scripts/org-keywords.lua&quot;</span></span>\n<span><a href=\"#cb2-331\"></a> <span>&gt;=&gt;</span> applyFilter def [] <span>&quot;scripts/elem-ids.lua&quot;</span></span>\n<span><a href=\"#cb2-332\"></a> <span>&gt;=&gt;</span> applyFilter def [] <span>&quot;scripts/footnote-commas.lua&quot;</span></span>\n<span><a href=\"#cb2-333\"></a> )</span>\n<span><a href=\"#cb2-334\"></a></span>\n<span><a href=\"#cb2-335\"></a><span>indexContext ::</span> [<span>Item</span> a] <span>-&gt;</span> <span>Context</span> a <span>-&gt;</span> <span>Context</span> <span>String</span></span>\n<span><a href=\"#cb2-336\"></a>indexContext posts itemContext <span>=</span></span>\n<span><a href=\"#cb2-337\"></a> listField <span>&quot;posts&quot;</span> itemContext (<span>return</span> posts)</span>\n<span><a href=\"#cb2-338\"></a> <span>`mappend`</span> defaultContext</span>\n<span><a href=\"#cb2-339\"></a></span>\n<span><a href=\"#cb2-340\"></a><span>photosContext ::</span> [<span>Item</span> a] <span>-&gt;</span> <span>Context</span> <span>String</span></span>\n<span><a href=\"#cb2-341\"></a>photosContext photos <span>=</span></span>\n<span><a href=\"#cb2-342\"></a> listField <span>&quot;photos&quot;</span> photoContext (<span>return</span> photos)</span>\n<span><a href=\"#cb2-343\"></a> <span>`mappend`</span> defaultContext</span>\n<span><a href=\"#cb2-344\"></a></span>\n<span><a href=\"#cb2-345\"></a><span>postContext ::</span> <span>String</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Tags</span> <span>-&gt;</span> <span>Context</span> <span>String</span></span>\n<span><a href=\"#cb2-346\"></a>postContext titleDateFormat dateFormat tags <span>=</span></span>\n<span><a href=\"#cb2-347\"></a> field <span>&quot;prev&quot;</span> (adjacentLogField (<span>-</span><span>1</span>) dateFormat)</span>\n<span><a href=\"#cb2-348\"></a> <span>`mappend`</span> field <span>&quot;next&quot;</span> (adjacentLogField <span>1</span> dateFormat)</span>\n<span><a href=\"#cb2-349\"></a> <span>`mappend`</span> dateFieldFromTitle <span>&quot;title&quot;</span> titleDateFormat</span>\n<span><a href=\"#cb2-350\"></a> <span>`mappend`</span> dateField <span>&quot;published&quot;</span> dateFormat</span>\n<span><a href=\"#cb2-351\"></a> <span>`mappend`</span> myDateField <span>&quot;updated&quot;</span> dateFormat</span>\n<span><a href=\"#cb2-352\"></a> <span>`mappend`</span> myTagsField <span>&quot;tags&quot;</span> tags</span>\n<span><a href=\"#cb2-353\"></a> <span>`mappend`</span> defaultContext</span>\n<span><a href=\"#cb2-354\"></a></span>\n<span><a href=\"#cb2-355\"></a><span>-- https://github.com/emmanueltouzery/hsexif/issues/23#issuecomment-2835135828</span></span>\n<span><a href=\"#cb2-356\"></a>formatNumeric f (<span>ExifRational</span> num den) <span>=</span> f num den <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-357\"></a>formatNumeric f (<span>ExifRationalList</span> values) <span>=</span> go values <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-358\"></a> <span>where</span></span>\n<span><a href=\"#cb2-359\"></a> go [] <span>=</span> <span>id</span></span>\n<span><a href=\"#cb2-360\"></a> go [(n, d)] <span>=</span> f n d</span>\n<span><a href=\"#cb2-361\"></a> go ((n, d) <span>:</span> ns) <span>=</span> f n d <span>.</span> <span>showString</span> <span>&quot;, &quot;</span> <span>.</span> go ns</span>\n<span><a href=\"#cb2-362\"></a>formatNumeric _ value <span>=</span> <span>show</span> value</span>\n<span><a href=\"#cb2-363\"></a></span>\n<span><a href=\"#cb2-364\"></a><span>formatAsNumber ::</span> <span>Int</span> <span>-&gt;</span> <span>ExifValue</span> <span>-&gt;</span> <span>String</span></span>\n<span><a href=\"#cb2-365\"></a>formatAsNumber n <span>=</span> formatNumeric fmt</span>\n<span><a href=\"#cb2-366\"></a> <span>where</span></span>\n<span><a href=\"#cb2-367\"></a> fmt num den s <span>=</span> trim0 (fltString num den) <span>++</span> s</span>\n<span><a href=\"#cb2-368\"></a> trim0 <span>=</span> <span>reverse</span> <span>.</span> <span>dropWhile</span> (<span>'.'</span> <span>==</span>) <span>.</span> <span>dropWhile</span> (<span>'0'</span> <span>==</span>) <span>.</span> <span>reverse</span></span>\n<span><a href=\"#cb2-369\"></a> fltString num den <span>=</span> showFFloat (<span>Just</span> n) (<span>fromIntegral</span> num <span>/</span> <span>fromIntegral</span><span> den ::</span> <span>Double</span>) <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-370\"></a></span>\n<span><a href=\"#cb2-371\"></a><span>ppExposureTime ::</span> <span>ExifValue</span> <span>-&gt;</span> <span>String</span></span>\n<span><a href=\"#cb2-372\"></a>ppExposureTime v<span>@</span>(<span>ExifRational</span> num den) <span>=</span></span>\n<span><a href=\"#cb2-373\"></a> <span>let</span> seconds <span>=</span> <span>fromIntegral</span> num <span>/</span> (<span>fromIntegral</span><span> den ::</span> <span>Double</span>)</span>\n<span><a href=\"#cb2-374\"></a> value</span>\n<span><a href=\"#cb2-375\"></a> <span>|</span> seconds <span>&lt;=</span> <span>0.25</span> <span>&amp;&amp;</span> seconds <span>&gt;</span> <span>0</span> <span>=</span> <span>&quot;1/&quot;</span> <span>++</span> <span>show</span> (<span>round</span> (<span>1</span> <span>/</span> seconds)<span> ::</span> <span>Int</span>)</span>\n<span><a href=\"#cb2-376\"></a> <span>|</span> <span>otherwise</span> <span>=</span> formatAsNumber <span>1</span> v</span>\n<span><a href=\"#cb2-377\"></a> <span>in</span> T.unpack <span>$</span> T.append (T.pack value) <span>&quot; sec.&quot;</span></span>\n<span><a href=\"#cb2-378\"></a>ppExposureTime v <span>=</span> <span>show</span> v</span>\n<span><a href=\"#cb2-379\"></a></span>\n<span><a href=\"#cb2-380\"></a><span>photoContext ::</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-381\"></a>photoContext <span>=</span></span>\n<span><a href=\"#cb2-382\"></a> dateField <span>&quot;published&quot;</span> dateFormat</span>\n<span><a href=\"#cb2-383\"></a> <span>`mappend`</span> urlField <span>&quot;url&quot;</span></span>\n<span><a href=\"#cb2-384\"></a> <span>`mappend`</span> pathField <span>&quot;path&quot;</span></span>\n<span><a href=\"#cb2-385\"></a> <span>`mappend`</span> titleField <span>&quot;title&quot;</span></span>\n<span><a href=\"#cb2-386\"></a> <span>`mappend`</span> thumbnailField <span>&quot;thumb&quot;</span></span>\n<span><a href=\"#cb2-387\"></a> <span>`mappend`</span> videoField <span>&quot;video&quot;</span></span>\n<span><a href=\"#cb2-388\"></a> <span>`mappend`</span> exifDateField <span>&quot;published&quot;</span> dateFormat</span>\n<span><a href=\"#cb2-389\"></a> <span>`mappend`</span> exifLatField <span>&quot;lat&quot;</span></span>\n<span><a href=\"#cb2-390\"></a> <span>`mappend`</span> exifLongField <span>&quot;lon&quot;</span></span>\n<span><a href=\"#cb2-391\"></a> <span>`mappend`</span> exifField <span>&quot;make&quot;</span> make <span>show</span></span>\n<span><a href=\"#cb2-392\"></a> <span>`mappend`</span> exifField <span>&quot;model&quot;</span> model <span>show</span></span>\n<span><a href=\"#cb2-393\"></a> <span>`mappend`</span> exifField <span>&quot;focallength&quot;</span> focalLength (formatAsFloatingPoint <span>2</span>)</span>\n<span><a href=\"#cb2-394\"></a> <span>`mappend`</span> exifField <span>&quot;aperture&quot;</span> apertureValue (formatAsFloatingPoint <span>2</span>)</span>\n<span><a href=\"#cb2-395\"></a> <span>`mappend`</span> exifField <span>&quot;exposure&quot;</span> exposureTime ppExposureTime</span>\n<span><a href=\"#cb2-396\"></a> <span>`mappend`</span> exifField <span>&quot;iso&quot;</span> isoSpeedRatings <span>show</span></span>\n<span><a href=\"#cb2-397\"></a> <span>`mappend`</span> locationField <span>&quot;loc&quot;</span></span>\n<span><a href=\"#cb2-398\"></a></span>\n<span><a href=\"#cb2-399\"></a><span>exifField ::</span> <span>String</span> <span>-&gt;</span> <span>ExifTag</span> <span>-&gt;</span> (<span>ExifValue</span> <span>-&gt;</span> <span>String</span>) <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-400\"></a>exifField key tag <span>print</span> <span>=</span></span>\n<span><a href=\"#cb2-401\"></a> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-402\"></a> metadata <span>&lt;-</span> exifMetadata item</span>\n<span><a href=\"#cb2-403\"></a> <span>case</span> M.lookup tag metadata <span>of</span></span>\n<span><a href=\"#cb2-404\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-405\"></a> <span>Just</span> value <span>-&gt;</span> <span>return</span> <span>$</span> <span>print</span> value</span>\n<span><a href=\"#cb2-406\"></a></span>\n<span><a href=\"#cb2-407\"></a><span>exifLatField ::</span> <span>String</span> <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-408\"></a>exifLatField key <span>=</span></span>\n<span><a href=\"#cb2-409\"></a> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-410\"></a> metadata <span>&lt;-</span> exifMetadata item</span>\n<span><a href=\"#cb2-411\"></a> <span>case</span> getGpsLatitudeLongitude metadata <span>of</span></span>\n<span><a href=\"#cb2-412\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-413\"></a> <span>Just</span> (lat, _) <span>-&gt;</span> <span>return</span> <span>$</span> <span>show</span> lat</span>\n<span><a href=\"#cb2-414\"></a></span>\n<span><a href=\"#cb2-415\"></a><span>exifLongField ::</span> <span>String</span> <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-416\"></a>exifLongField key <span>=</span></span>\n<span><a href=\"#cb2-417\"></a> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-418\"></a> metadata <span>&lt;-</span> exifMetadata item</span>\n<span><a href=\"#cb2-419\"></a> <span>case</span> getGpsLatitudeLongitude metadata <span>of</span></span>\n<span><a href=\"#cb2-420\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-421\"></a> <span>Just</span> (_, lon) <span>-&gt;</span> <span>return</span> <span>$</span> <span>show</span> lon</span>\n<span><a href=\"#cb2-422\"></a></span>\n<span><a href=\"#cb2-423\"></a><span>exifDateField ::</span> <span>String</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-424\"></a>exifDateField key format <span>=</span></span>\n<span><a href=\"#cb2-425\"></a> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-426\"></a> metadata <span>&lt;-</span> exifMetadata item</span>\n<span><a href=\"#cb2-427\"></a> <span>case</span> getDateTimeOriginal metadata <span>of</span></span>\n<span><a href=\"#cb2-428\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-429\"></a> <span>Just</span> date <span>-&gt;</span> <span>return</span> <span>$</span> formatTime defaultTimeLocale format date</span>\n<span><a href=\"#cb2-430\"></a></span>\n<span><a href=\"#cb2-431\"></a><span>-- </span><span>TODO</span><span> don't load metadata individually for each field</span></span>\n<span><a href=\"#cb2-432\"></a><span>exifMetadata ::</span> <span>Item</span> a <span>-&gt;</span> <span>Compiler</span> (<span>M.Map</span> <span>ExifTag</span> <span>ExifValue</span>)</span>\n<span><a href=\"#cb2-433\"></a>exifMetadata item <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-434\"></a> <span>let</span> identifier <span>=</span> itemIdentifier item</span>\n<span><a href=\"#cb2-435\"></a> exifData <span>&lt;-</span> unsafeCompiler (parseFileExif (toFilePath identifier))</span>\n<span><a href=\"#cb2-436\"></a> <span>return</span> <span>$</span> fromRight M.empty exifData</span>\n<span><a href=\"#cb2-437\"></a></span>\n<span><a href=\"#cb2-438\"></a><span>data</span> <span>PhotoLocation</span> <span>=</span> <span>PhotoLocation</span></span>\n<span><a href=\"#cb2-439\"></a> {<span> displayName ::</span> <span>T.Text</span>,</span>\n<span><a href=\"#cb2-440\"></a><span> addressMap ::</span> <span>HM.HashMap</span> <span>T.Text</span> <span>T.Text</span></span>\n<span><a href=\"#cb2-441\"></a> }</span>\n<span><a href=\"#cb2-442\"></a> <span>deriving</span> (<span>Show</span>)</span>\n<span><a href=\"#cb2-443\"></a></span>\n<span><a href=\"#cb2-444\"></a><span>instance</span> <span>FromJSON</span> <span>PhotoLocation</span> <span>where</span></span>\n<span><a href=\"#cb2-445\"></a> parseJSON <span>=</span> withObject <span>&quot;PhotoLocation&quot;</span> <span>$</span> \\v <span>-&gt;</span></span>\n<span><a href=\"#cb2-446\"></a> <span>PhotoLocation</span></span>\n<span><a href=\"#cb2-447\"></a> <span>&lt;$&gt;</span> v <span>.:</span> <span>&quot;display_name&quot;</span></span>\n<span><a href=\"#cb2-448\"></a> <span>&lt;*&gt;</span> v <span>.:</span> <span>&quot;address&quot;</span></span>\n<span><a href=\"#cb2-449\"></a></span>\n<span><a href=\"#cb2-450\"></a><span>readCachedLocation ::</span> <span>FilePath</span> <span>-&gt;</span> <span>IO</span> (<span>Either</span> <span>String</span> <span>PhotoLocation</span>)</span>\n<span><a href=\"#cb2-451\"></a>readCachedLocation photoPath <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-452\"></a> <span>let</span> cacheFile <span>=</span> <span>&quot;reverse-geocoding/&quot;</span> <span>++</span> takeFileName photoPath <span>++</span> <span>&quot;.json&quot;</span></span>\n<span><a href=\"#cb2-453\"></a> exists <span>&lt;-</span> doesFileExist cacheFile</span>\n<span><a href=\"#cb2-454\"></a> <span>if</span> <span>not</span> exists</span>\n<span><a href=\"#cb2-455\"></a> <span>then</span> <span>return</span> <span>$</span> <span>Left</span> <span>&quot;Cache file not found&quot;</span></span>\n<span><a href=\"#cb2-456\"></a> <span>else</span> eitherDecode <span>&lt;$&gt;</span> BSL.readFile cacheFile</span>\n<span><a href=\"#cb2-457\"></a></span>\n<span><a href=\"#cb2-458\"></a><span>formatLocation ::</span> <span>HM.HashMap</span> <span>T.Text</span> <span>T.Text</span> <span>-&gt;</span> <span>T.Text</span></span>\n<span><a href=\"#cb2-459\"></a>formatLocation m <span>=</span></span>\n<span><a href=\"#cb2-460\"></a> <span>let</span> country <span>=</span> HM.lookup <span>&quot;country&quot;</span> m</span>\n<span><a href=\"#cb2-461\"></a> city <span>=</span> HM.lookup <span>&quot;city&quot;</span> m</span>\n<span><a href=\"#cb2-462\"></a> state_district <span>=</span> HM.lookup <span>&quot;state_district&quot;</span> m</span>\n<span><a href=\"#cb2-463\"></a> heirarchy</span>\n<span><a href=\"#cb2-464\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;United States&quot;</span> <span>&amp;&amp;</span> city <span>==</span> <span>Just</span> <span>&quot;New York&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-465\"></a> [ [<span>&quot;borough&quot;</span>],</span>\n<span><a href=\"#cb2-466\"></a> [<span>&quot;state&quot;</span>],</span>\n<span><a href=\"#cb2-467\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-468\"></a> ]</span>\n<span><a href=\"#cb2-469\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;United States&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-470\"></a> [ [<span>&quot;city&quot;</span>, <span>&quot;town&quot;</span>, <span>&quot;village&quot;</span>, <span>&quot;road&quot;</span>],</span>\n<span><a href=\"#cb2-471\"></a> [<span>&quot;state&quot;</span>],</span>\n<span><a href=\"#cb2-472\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-473\"></a> ]</span>\n<span><a href=\"#cb2-474\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;United Kingdom&quot;</span> <span>&amp;&amp;</span> city <span>==</span> <span>Just</span> <span>&quot;London&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-475\"></a> [ [<span>&quot;suburb&quot;</span>],</span>\n<span><a href=\"#cb2-476\"></a> [<span>&quot;city&quot;</span>],</span>\n<span><a href=\"#cb2-477\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-478\"></a> ]</span>\n<span><a href=\"#cb2-479\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;United Kingdom&quot;</span> <span>&amp;&amp;</span> state_district <span>==</span> <span>Just</span> <span>&quot;Greater London&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-480\"></a> [ [<span>&quot;city&quot;</span>],</span>\n<span><a href=\"#cb2-481\"></a> [<span>&quot;state_district&quot;</span>],</span>\n<span><a href=\"#cb2-482\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-483\"></a> ]</span>\n<span><a href=\"#cb2-484\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;United Kingdom&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-485\"></a> [ [<span>&quot;city&quot;</span>, <span>&quot;town&quot;</span>, <span>&quot;village&quot;</span>],</span>\n<span><a href=\"#cb2-486\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-487\"></a> ]</span>\n<span><a href=\"#cb2-488\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;France&quot;</span> <span>&amp;&amp;</span> city <span>==</span> <span>Just</span> <span>&quot;Paris&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-489\"></a> [ [<span>&quot;suburb&quot;</span>],</span>\n<span><a href=\"#cb2-490\"></a> [<span>&quot;city&quot;</span>],</span>\n<span><a href=\"#cb2-491\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-492\"></a> ]</span>\n<span><a href=\"#cb2-493\"></a> <span>|</span> country <span>==</span> <span>Just</span> <span>&quot;Italy&quot;</span> <span>=</span></span>\n<span><a href=\"#cb2-494\"></a> [ [<span>&quot;quarter&quot;</span>],</span>\n<span><a href=\"#cb2-495\"></a> [<span>&quot;city&quot;</span>, <span>&quot;town&quot;</span>, <span>&quot;village&quot;</span>],</span>\n<span><a href=\"#cb2-496\"></a> [<span>&quot;state&quot;</span>],</span>\n<span><a href=\"#cb2-497\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-498\"></a> ]</span>\n<span><a href=\"#cb2-499\"></a> <span>|</span> <span>otherwise</span> <span>=</span></span>\n<span><a href=\"#cb2-500\"></a> [ [<span>&quot;historic&quot;</span>],</span>\n<span><a href=\"#cb2-501\"></a> [<span>&quot;city&quot;</span>, <span>&quot;state&quot;</span>, <span>&quot;region&quot;</span>, <span>&quot;town&quot;</span>],</span>\n<span><a href=\"#cb2-502\"></a> [<span>&quot;country&quot;</span>]</span>\n<span><a href=\"#cb2-503\"></a> ]</span>\n<span><a href=\"#cb2-504\"></a> lookupFirst ks <span>=</span> listToMaybe <span>$</span> mapMaybe (<span>`HM.lookup`</span> m) ks</span>\n<span><a href=\"#cb2-505\"></a> fields <span>=</span> <span>map</span> lookupFirst heirarchy</span>\n<span><a href=\"#cb2-506\"></a> <span>in</span> T.intercalate <span>&quot;, &quot;</span> (catMaybes fields)</span>\n<span><a href=\"#cb2-507\"></a></span>\n<span><a href=\"#cb2-508\"></a><span>locationField ::</span> <span>String</span> <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-509\"></a>locationField key <span>=</span> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-510\"></a> <span>let</span> fp <span>=</span> toFilePath (itemIdentifier item)</span>\n<span><a href=\"#cb2-511\"></a> eLoc <span>&lt;-</span> unsafeCompiler <span>$</span> readCachedLocation fp</span>\n<span><a href=\"#cb2-512\"></a> <span>case</span> eLoc <span>of</span></span>\n<span><a href=\"#cb2-513\"></a> <span>Left</span> _ <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-514\"></a> <span>Right</span> loc <span>-&gt;</span></span>\n<span><a href=\"#cb2-515\"></a> <span>let</span> txt <span>=</span> formatLocation (addressMap loc)</span>\n<span><a href=\"#cb2-516\"></a> <span>in</span> <span>if</span> T.null txt <span>then</span> noResult <span>&quot;&quot;</span> <span>else</span> <span>return</span> (T.unpack txt)</span>\n<span><a href=\"#cb2-517\"></a></span>\n<span><a href=\"#cb2-518\"></a><span>myDateField ::</span> <span>String</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Context</span> <span>String</span></span>\n<span><a href=\"#cb2-519\"></a>myDateField name format <span>=</span></span>\n<span><a href=\"#cb2-520\"></a> field name <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-521\"></a> metadata <span>&lt;-</span> getMetadata (itemIdentifier item)</span>\n<span><a href=\"#cb2-522\"></a> <span>let</span><span> date ::</span> <span>Maybe</span> <span>UTCTime</span></span>\n<span><a href=\"#cb2-523\"></a> date <span>=</span> lookupString name metadata <span>&gt;&gt;=</span> parseTimeM <span>True</span> defaultTimeLocale <span>&quot;%Y-%m-%d&quot;</span></span>\n<span><a href=\"#cb2-524\"></a> <span>case</span> date <span>of</span></span>\n<span><a href=\"#cb2-525\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-526\"></a> <span>Just</span> date <span>-&gt;</span> <span>return</span> <span>$</span> formatTime defaultTimeLocale format date</span>\n<span><a href=\"#cb2-527\"></a></span>\n<span><a href=\"#cb2-528\"></a><span>dateFieldFromTitle ::</span> <span>String</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Context</span> <span>String</span></span>\n<span><a href=\"#cb2-529\"></a>dateFieldFromTitle key format <span>=</span></span>\n<span><a href=\"#cb2-530\"></a> field key <span>$</span> \\item <span>-&gt;</span></span>\n<span><a href=\"#cb2-531\"></a> <span>case</span> dateFromTitle item <span>of</span></span>\n<span><a href=\"#cb2-532\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-533\"></a> <span>Just</span> date <span>-&gt;</span></span>\n<span><a href=\"#cb2-534\"></a> <span>return</span> <span>$</span> formatTime defaultTimeLocale format date</span>\n<span><a href=\"#cb2-535\"></a></span>\n<span><a href=\"#cb2-536\"></a><span>thumbnailField ::</span> <span>String</span> <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-537\"></a>thumbnailField key <span>=</span> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-538\"></a> mRoute <span>&lt;-</span> getRoute (itemIdentifier item)</span>\n<span><a href=\"#cb2-539\"></a> <span>case</span> mRoute <span>of</span></span>\n<span><a href=\"#cb2-540\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-541\"></a> <span>Just</span> url <span>-&gt;</span></span>\n<span><a href=\"#cb2-542\"></a> <span>if</span> <span>&quot;.mp4&quot;</span> <span>`L.isSuffixOf`</span> url</span>\n<span><a href=\"#cb2-543\"></a> <span>then</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-544\"></a> <span>else</span></span>\n<span><a href=\"#cb2-545\"></a> <span>return</span> <span>$</span></span>\n<span><a href=\"#cb2-546\"></a> T.unpack <span>$</span></span>\n<span><a href=\"#cb2-547\"></a> T.replace <span>&quot;photos/&quot;</span> <span>&quot;photos/thumb/&quot;</span> (T.pack url)</span>\n<span><a href=\"#cb2-548\"></a></span>\n<span><a href=\"#cb2-549\"></a><span>videoField ::</span> <span>String</span> <span>-&gt;</span> <span>Context</span> a</span>\n<span><a href=\"#cb2-550\"></a>videoField key <span>=</span> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-551\"></a> mRoute <span>&lt;-</span> getRoute (itemIdentifier item)</span>\n<span><a href=\"#cb2-552\"></a> <span>case</span> mRoute <span>of</span></span>\n<span><a href=\"#cb2-553\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-554\"></a> <span>Just</span> url <span>-&gt;</span></span>\n<span><a href=\"#cb2-555\"></a> <span>if</span> <span>&quot;.mp4&quot;</span> <span>`L.isSuffixOf`</span> url</span>\n<span><a href=\"#cb2-556\"></a> <span>then</span></span>\n<span><a href=\"#cb2-557\"></a> <span>return</span> <span>$</span></span>\n<span><a href=\"#cb2-558\"></a> T.unpack <span>$</span></span>\n<span><a href=\"#cb2-559\"></a> T.replace <span>&quot;static/photos/&quot;</span> <span>&quot;photos/&quot;</span> (T.pack url)</span>\n<span><a href=\"#cb2-560\"></a> <span>else</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-561\"></a></span>\n<span><a href=\"#cb2-562\"></a><span>myTagsField ::</span> <span>String</span> <span>-&gt;</span> <span>Tags</span> <span>-&gt;</span> <span>Context</span> <span>String</span></span>\n<span><a href=\"#cb2-563\"></a>myTagsField key tags <span>=</span> field key <span>$</span> \\item <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-564\"></a> tags' <span>&lt;-</span> getTags <span>$</span> itemIdentifier item</span>\n<span><a href=\"#cb2-565\"></a> <span>if</span> <span>null</span> tags'</span>\n<span><a href=\"#cb2-566\"></a> <span>then</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-567\"></a> <span>else</span> <span>do</span></span>\n<span><a href=\"#cb2-568\"></a> links <span>&lt;-</span> forM tags' <span>$</span> \\tag <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-569\"></a> route' <span>&lt;-</span> getRoute <span>$</span> tagsMakeId tags tag</span>\n<span><a href=\"#cb2-570\"></a> <span>return</span> <span>$</span> simpleRenderLink tag route'</span>\n<span><a href=\"#cb2-571\"></a> <span>return</span> <span>$</span> renderHtml <span>$</span> <span>mconcat</span> <span>.</span> L.intersperse <span>&quot;, &quot;</span> <span>$</span> catMaybes links</span>\n<span><a href=\"#cb2-572\"></a></span>\n<span><a href=\"#cb2-573\"></a><span>renderTag ::</span> <span>String</span> <span>-&gt;</span> <span>Maybe</span> <span>FilePath</span> <span>-&gt;</span> <span>Maybe</span> <span>H.Html</span></span>\n<span><a href=\"#cb2-574\"></a>renderTag _ <span>Nothing</span> <span>=</span> <span>Nothing</span></span>\n<span><a href=\"#cb2-575\"></a>renderTag tag (<span>Just</span> filePath) <span>=</span></span>\n<span><a href=\"#cb2-576\"></a> <span>Just</span> <span>$</span></span>\n<span><a href=\"#cb2-577\"></a> H.a <span>!</span> A.href (toValue <span>$</span> toUrl filePath) <span>$</span></span>\n<span><a href=\"#cb2-578\"></a> toHtml tag</span>\n<span><a href=\"#cb2-579\"></a></span>\n<span><a href=\"#cb2-580\"></a><span>isPublished ::</span> <span>Item</span> a <span>-&gt;</span> <span>Compiler</span> <span>Bool</span></span>\n<span><a href=\"#cb2-581\"></a>isPublished item <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-582\"></a> metadata <span>&lt;-</span> getMetadata (itemIdentifier item)</span>\n<span><a href=\"#cb2-583\"></a> <span>case</span> lookupString <span>&quot;published&quot;</span> metadata <span>of</span></span>\n<span><a href=\"#cb2-584\"></a> <span>Just</span> value <span>-&gt;</span> <span>return</span> (value <span>/=</span> <span>&quot;false&quot;</span>)</span>\n<span><a href=\"#cb2-585\"></a> <span>Nothing</span> <span>-&gt;</span> <span>return</span> (isJust (dateFromTitle item))</span>\n<span><a href=\"#cb2-586\"></a></span>\n<span><a href=\"#cb2-587\"></a><span>isNotDraft ::</span> <span>Item</span> a <span>-&gt;</span> <span>Compiler</span> <span>Bool</span></span>\n<span><a href=\"#cb2-588\"></a>isNotDraft item <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-589\"></a> metadata <span>&lt;-</span> getMetadata (itemIdentifier item)</span>\n<span><a href=\"#cb2-590\"></a> <span>return</span> <span>$</span> isNotDraftMeta metadata</span>\n<span><a href=\"#cb2-591\"></a></span>\n<span><a href=\"#cb2-592\"></a><span>isNotDraftMeta ::</span> <span>Metadata</span> <span>-&gt;</span> <span>Bool</span></span>\n<span><a href=\"#cb2-593\"></a>isNotDraftMeta metadata <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-594\"></a> <span>case</span> lookupString <span>&quot;published&quot;</span> metadata <span>of</span></span>\n<span><a href=\"#cb2-595\"></a> <span>Just</span> value <span>-&gt;</span> value <span>/=</span> <span>&quot;false&quot;</span></span>\n<span><a href=\"#cb2-596\"></a> <span>Nothing</span> <span>-&gt;</span> <span>True</span></span>\n<span><a href=\"#cb2-597\"></a></span>\n<span><a href=\"#cb2-598\"></a><span>dateFromTitle ::</span> <span>Item</span> a <span>-&gt;</span> <span>Maybe</span> <span>UTCTime</span></span>\n<span><a href=\"#cb2-599\"></a>dateFromTitle item <span>=</span></span>\n<span><a href=\"#cb2-600\"></a> <span>let</span> filePath <span>=</span> toFilePath (itemIdentifier item)</span>\n<span><a href=\"#cb2-601\"></a> title <span>=</span> takeBaseName filePath</span>\n<span><a href=\"#cb2-602\"></a> <span>in</span> parseTimeM <span>True</span> defaultTimeLocale <span>&quot;%Y-%m-%d&quot;</span> title</span>\n<span><a href=\"#cb2-603\"></a></span>\n<span><a href=\"#cb2-604\"></a><span>rewriteLinks ::</span> <span>String</span> <span>-&gt;</span> <span>String</span></span>\n<span><a href=\"#cb2-605\"></a>rewriteLinks url</span>\n<span><a href=\"#cb2-606\"></a> <span>|</span> <span>&quot;://&quot;</span> <span>`T.isInfixOf`</span> turl <span>=</span> url</span>\n<span><a href=\"#cb2-607\"></a> <span>-- workaround https://github.com/jgm/pandoc/issues/6916</span></span>\n<span><a href=\"#cb2-608\"></a> <span>|</span> <span>&quot;::&quot;</span> <span>`T.isInfixOf`</span> turl <span>=</span></span>\n<span><a href=\"#cb2-609\"></a> <span>let</span> (basePart, rest) <span>=</span> T.breakOn <span>&quot;::&quot;</span> turl</span>\n<span><a href=\"#cb2-610\"></a> cleanedBase <span>=</span> replaceExts basePart</span>\n<span><a href=\"#cb2-611\"></a> headingPart <span>=</span> T.drop <span>2</span> rest <span>-- Remove the &quot;::&quot;</span></span>\n<span><a href=\"#cb2-612\"></a> generatedId <span>=</span> generateId headingPart</span>\n<span><a href=\"#cb2-613\"></a> <span>in</span> T.unpack <span>$</span> cleanedBase <span>&lt;&gt;</span> <span>&quot;#&quot;</span> <span>&lt;&gt;</span> generatedId</span>\n<span><a href=\"#cb2-614\"></a> <span>|</span> <span>otherwise</span> <span>=</span></span>\n<span><a href=\"#cb2-615\"></a> <span>let</span> (base, fragment) <span>=</span> T.breakOn <span>&quot;#&quot;</span> turl</span>\n<span><a href=\"#cb2-616\"></a> processedBase <span>=</span> replaceExts base</span>\n<span><a href=\"#cb2-617\"></a> <span>in</span> T.unpack <span>$</span> processedBase <span>&lt;&gt;</span> fragment</span>\n<span><a href=\"#cb2-618\"></a> <span>where</span></span>\n<span><a href=\"#cb2-619\"></a> turl <span>=</span> T.pack url</span>\n<span><a href=\"#cb2-620\"></a> replaceExts <span>=</span> replaceExt <span>&quot;.md&quot;</span> <span>&quot;.html&quot;</span> <span>.</span> replaceExt <span>&quot;.org&quot;</span> <span>&quot;.html&quot;</span></span>\n<span><a href=\"#cb2-621\"></a></span>\n<span><a href=\"#cb2-622\"></a><span>replaceExt ::</span> <span>T.Text</span> <span>-&gt;</span> <span>T.Text</span> <span>-&gt;</span> <span>T.Text</span> <span>-&gt;</span> <span>T.Text</span></span>\n<span><a href=\"#cb2-623\"></a>replaceExt oldExt newExt url <span>=</span></span>\n<span><a href=\"#cb2-624\"></a> <span>let</span> (base, fragment) <span>=</span> T.breakOn <span>&quot;#&quot;</span> url</span>\n<span><a href=\"#cb2-625\"></a> cleanedBase <span>=</span> <span>if</span> <span>&quot;::&quot;</span> <span>`T.isSuffixOf`</span> base <span>then</span> T.dropEnd <span>2</span> base <span>else</span> base</span>\n<span><a href=\"#cb2-626\"></a> processedBase <span>=</span></span>\n<span><a href=\"#cb2-627\"></a> <span>if</span> oldExt <span>`T.isSuffixOf`</span> cleanedBase</span>\n<span><a href=\"#cb2-628\"></a> <span>then</span> T.replace oldExt newExt cleanedBase</span>\n<span><a href=\"#cb2-629\"></a> <span>else</span> cleanedBase</span>\n<span><a href=\"#cb2-630\"></a> <span>in</span> processedBase <span>&lt;&gt;</span> fragment</span>\n<span><a href=\"#cb2-631\"></a></span>\n<span><a href=\"#cb2-632\"></a><span>generateId ::</span> <span>T.Text</span> <span>-&gt;</span> <span>T.Text</span></span>\n<span><a href=\"#cb2-633\"></a>generateId heading <span>=</span></span>\n<span><a href=\"#cb2-634\"></a> <span>let</span> lower <span>=</span> T.toLower heading</span>\n<span><a href=\"#cb2-635\"></a> spaced <span>=</span> T.replace (T.pack <span>&quot; &quot;</span>) (T.pack <span>&quot;-&quot;</span>) lower</span>\n<span><a href=\"#cb2-636\"></a> filtered <span>=</span> T.filter (\\c <span>-&gt;</span> <span>isAlphaNum</span> c <span>||</span> c <span>==</span> <span>'-'</span> <span>||</span> c <span>==</span> <span>'_'</span> <span>||</span> c <span>==</span> <span>'.'</span>) spaced</span>\n<span><a href=\"#cb2-637\"></a> parts <span>=</span> T.split (<span>==</span> <span>'-'</span>) filtered</span>\n<span><a href=\"#cb2-638\"></a> nonEmptyParts <span>=</span> <span>filter</span> (<span>not</span> <span>.</span> T.null) parts</span>\n<span><a href=\"#cb2-639\"></a> cleaned <span>=</span> <span>if</span> <span>null</span> nonEmptyParts <span>then</span> T.pack <span>&quot;section&quot;</span> <span>else</span> T.intercalate (T.pack <span>&quot;-&quot;</span>) nonEmptyParts</span>\n<span><a href=\"#cb2-640\"></a> <span>in</span> cleaned</span>\n<span><a href=\"#cb2-641\"></a></span>\n<span><a href=\"#cb2-642\"></a><span>adjacentLogField ::</span> <span>Int</span> <span>-&gt;</span> <span>String</span> <span>-&gt;</span> <span>Item</span> <span>String</span> <span>-&gt;</span> <span>Compiler</span> <span>String</span></span>\n<span><a href=\"#cb2-643\"></a>adjacentLogField offset format item <span>=</span> <span>do</span></span>\n<span><a href=\"#cb2-644\"></a> posts <span>&lt;-</span> loadAllSnapshots logFiles <span>&quot;body&quot;</span><span> ::</span> <span>Compiler</span> [<span>Item</span> <span>String</span>]</span>\n<span><a href=\"#cb2-645\"></a> <span>let</span> adjacent <span>=</span> getAdjacentLog posts item offset</span>\n<span><a href=\"#cb2-646\"></a> <span>case</span> adjacent <span>of</span></span>\n<span><a href=\"#cb2-647\"></a> <span>Nothing</span> <span>-&gt;</span> noResult <span>&quot;&quot;</span></span>\n<span><a href=\"#cb2-648\"></a> <span>Just</span> a <span>-&gt;</span> <span>do</span></span>\n<span><a href=\"#cb2-649\"></a> mroute <span>&lt;-</span> getRoute (itemIdentifier a)</span>\n<span><a href=\"#cb2-650\"></a> <span>let</span> filePath <span>=</span> toFilePath (itemIdentifier item)</span>\n<span><a href=\"#cb2-651\"></a> title <span>=</span> takeBaseName filePath</span>\n<span><a href=\"#cb2-652\"></a> date <span>=</span> <span>fmap</span> (formatTime defaultTimeLocale format) (dateFromTitle a)</span>\n<span><a href=\"#cb2-653\"></a> label <span>=</span> fromMaybe title date</span>\n<span><a href=\"#cb2-654\"></a> <span>return</span> <span>$</span> <span>maybe</span> <span>&quot;&quot;</span> (\\r <span>-&gt;</span> <span>&quot;&lt;a href=\\&quot;&quot;</span> <span>++</span> r <span>++</span> <span>&quot;\\&quot;&gt;&quot;</span> <span>++</span> label <span>++</span> <span>&quot;&lt;/a&gt;&quot;</span>) mroute</span>\n<span><a href=\"#cb2-655\"></a></span>\n<span><a href=\"#cb2-656\"></a><span>getAdjacentLog ::</span> [<span>Item</span> a] <span>-&gt;</span> <span>Item</span> b <span>-&gt;</span> <span>Int</span> <span>-&gt;</span> <span>Maybe</span> (<span>Item</span> a)</span>\n<span><a href=\"#cb2-657\"></a>getAdjacentLog posts current offset <span>=</span></span>\n<span><a href=\"#cb2-658\"></a> <span>case</span> L.elemIndex (itemIdentifier current) (<span>map</span> itemIdentifier posts) <span>of</span></span>\n<span><a href=\"#cb2-659\"></a> <span>Nothing</span> <span>-&gt;</span> <span>Nothing</span></span>\n<span><a href=\"#cb2-660\"></a> <span>Just</span> idx <span>-&gt;</span></span>\n<span><a href=\"#cb2-661\"></a> <span>let</span> newIndex <span>=</span> idx <span>+</span> offset</span>\n<span><a href=\"#cb2-662\"></a> <span>in</span> <span>if</span> newIndex <span>&gt;=</span> <span>0</span> <span>&amp;&amp;</span> newIndex <span>&lt;</span> <span>length</span> posts</span>\n<span><a href=\"#cb2-663\"></a> <span>then</span> <span>Just</span> (posts <span>!!</span> newIndex)</span>\n<span><a href=\"#cb2-664\"></a> <span>else</span> <span>Nothing</span></span>\n<span><a href=\"#cb2-665\"></a></span>\n<span><a href=\"#cb2-666\"></a><span>titleCase ::</span> <span>String</span> <span>-&gt;</span> <span>String</span></span>\n<span><a href=\"#cb2-667\"></a>titleCase (x <span>:</span> xs) <span>=</span> C.toUpper x <span>:</span> <span>map</span> C.toLower xs</span>\n<span><a href=\"#cb2-668\"></a></span>\n<span><a href=\"#cb2-669\"></a><span>bibDate ::</span> <span>Bib</span> <span>-&gt;</span> <span>UTCTime</span></span>\n<span><a href=\"#cb2-670\"></a>bibDate b <span>=</span> <span>let</span></span>\n<span><a href=\"#cb2-671\"></a> latexifyPlain' <span>=</span> fromRight (<span>error</span> <span>$</span> <span>&quot;bibDate for entry &quot;</span> <span>&lt;&gt;</span> Bib.name b) <span>.</span> latexifyPlain</span>\n<span><a href=\"#cb2-672\"></a> date <span>=</span> latexifyPlain' <span>$</span> fromMaybe (<span>error</span> <span>$</span> <span>&quot;bibDate: no date in entry &quot;</span> <span>&lt;&gt;</span> Bib.name b) <span>$</span> bibIndex b <span>&quot;date&quot;</span></span>\n<span><a href=\"#cb2-673\"></a> parsed <span>=</span> parseTimeOrError <span>True</span> defaultTimeLocale <span>&quot;%Y-%m-%d&quot;</span><span> date ::</span> <span>UTCTime</span></span>\n<span><a href=\"#cb2-674\"></a> <span>in</span> parsed</span></code></pre></div>\n<p><span>The directory tree looks something like,</span></p>\n<pre><code>./ieee-with-url.csl\n./references.bib\n./scripts/anchor-links.lua\n./scripts/elem-ids.lua\n./scripts/footnote-commas.lua\n./static/about.org\n./static/articles.org\n./static/home.org\n./static/index.org\n./static/logs.org\n./static/news.org\n./static/papers.org\n./static/photos.org\n./static/research.org\n./static/keys\n./static/code.css\n./static/style.css\n./static/favicon.ico\n./static/rss.svg\n./static/2023-10-09.md\n./static/2023-10-16.md\n./static/2023-10-23.md\n./static/...\n./static/fonts/...\n./static/images/...\n./static/papers/...\n./static/photos/...\n./static/resources/...\n./templates/atom-item.xml\n./templates/atom.xml\n./templates/default.html\n./templates/log.html\n./templates/post-list.html\n./templates/post.html\n./templates/sitemap.xml\n./templates/tag.html\n</code></pre>\n<p><span>NB this is using <a href=\"https://gitlab.sac-home.org/tema/artem-blog/-/blob/master/BibHakyll.hs\">BibHakyll.hs</a>\nand <a href=\"https://gitlab.sac-home.org/tema/artem-blog/-/blob/master/Bib.hs\">Bib.hs</a>.</span></p>", 9 "content_type": "html", 10 "categories": [], 11 "source": "https://ryan.freumh.org/atom.xml" 12}