<?xml version="1.0" encoding="ISO-8859-1"?>
<rss version="2.0">
    <channel>
        <title>Common Lisp Project of the Day</title>
        <link>http://40ants.com/lisp-project-of-the-day/</link>
        <generator>xml-emitter</generator>
        <language>en-us</language>
        <item>
            <title>litterae</title>
            <link>http://40ants.com/lisp-project-of-the-day/2021/03/0220-litterae.html</link>
            <description>&lt;p&gt;This is yet another Common Lisp documentation builder.&lt;/p&gt;
&lt;p&gt;It renders beautiful one-page docs. Sadly, Litterae itself has no documentation. I&apos;ve used it to document Teddy and also created a template project for you:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cl-doc-systems/litterae&quot;&gt;https://github.com/cl-doc-systems/litterae&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Why Litterae can be interesting for you:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;It uses README.md as documentation source.&lt;/li&gt;&lt;li&gt;Litterae builds API reference from docstrings.&lt;/li&gt;&lt;li&gt;It provides four color themes.&lt;/li&gt;&lt;li&gt;It uses &lt;a href=&quot;https://github.com/fukamachi/lsx&quot;&gt;LSX&lt;/a&gt; for templating and probably there is a way   to create a custom HTML.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;However, there are many problems with Litterae. It seems not mature enough to use in my projects. To name a single feature I miss is cross-referencing. That is the main reason, why I&apos;ll not use it for my libraries.&lt;/p&gt;
</description>
            <pubDate>Fri, 26 Mar 2021 00:55:49 +0300</pubDate>
        </item>
        <item>
            <title>declt</title>
            <link>http://40ants.com/lisp-project-of-the-day/2021/01/0219-declt.html</link>
            <description>&lt;p&gt;This is the documentation builder behind &lt;a href=&quot;https://quickref.common-lisp.net/&quot;&gt;Quickref&lt;/a&gt; site. It is good for generating API references for third party libraries.&lt;/p&gt;
&lt;p&gt;Most interesting features of &lt;code&gt;Declt&lt;/code&gt; are:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;code&gt;Declt&lt;/code&gt; uses &lt;a href=&quot;https://www.gnu.org/software/texinfo/manual/texinfo/texinfo.html&quot;&gt;Texinfo file format&lt;/a&gt; for intermediate document store.   This makes it possible to generate not only HTML but also PDF and other   output formats.&lt;/li&gt;&lt;li&gt;It can automatically include license text into the documentation. But   this works only for a number of popular licenses like &lt;code&gt;MIT&lt;/code&gt;, &lt;code&gt;BSD&lt;/code&gt;, &lt;code&gt;GPL&lt;/code&gt;,   &lt;code&gt;LGPL&lt;/code&gt; and &lt;code&gt;BOOST&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;As always, I&apos;ve created a template project, ready to be used:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cl-doc-systems/declt&quot;&gt;https://github.com/cl-doc-systems/declt&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here is how it is rendered in HTML:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cl-doc-systems.github.io/declt/&quot;&gt;https://cl-doc-systems.github.io/declt/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And in PDF:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cl-doc-systems.github.io/declt/index.pdf&quot;&gt;https://cl-doc-systems.github.io/declt/index.pdf&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Sadly, &lt;code&gt;Declt&lt;/code&gt; does not support markup in docstrings and cross-referencing does not work there.&lt;/p&gt;
&lt;p&gt;Some other pros and cons are listed on &lt;a href=&quot;https://cl-doc-systems.github.io/declt/#Pros-_0026-Cons&quot;&gt;example site&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Remember, all example projects from &lt;a href=&quot;https://github.com/cl-doc-systems&quot;&gt;https://github.com/cl-doc-systems&lt;/a&gt; include a build script and GitHub Action to update documentation on every commit!&lt;/p&gt;
</description>
            <pubDate>Sun, 17 Jan 2021 16:58:46 +0300</pubDate>
        </item>
        <item>
            <title>atdoc</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/12/0218-atdoc.html</link>
            <description>&lt;p&gt;This is yet another documentation builder for CL.&lt;/p&gt;
&lt;p&gt;Its unique features are a special markup and ability to render not only HTML, but also PDF and Info files.&lt;/p&gt;
&lt;p&gt;As always, I&apos;ve created an example project which can be used as a template for your own library. Here how it is rendered in HTML:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cl-doc-systems.github.io/atdoc/&quot;&gt;https://cl-doc-systems.github.io/atdoc/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is how it is &lt;a href=&quot;https://cl-doc-systems.github.io/atdoc/latex/documentation.pdf&quot;&gt;rendered into PDF&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;max-width: 100%&quot; src=&quot;../../media/0218/atdoc.png&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Beautiful. Isn&apos;t it?&lt;/p&gt;
&lt;p&gt;More pros and cons of &lt;code&gt;ATDOC&lt;/code&gt; are listed in the repository&apos;s README:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cl-doc-systems/atdoc&quot;&gt;https://github.com/cl-doc-systems/atdoc&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Remember, all example projects from &lt;a href=&quot;https://github.com/cl-doc-systems&quot;&gt;https://github.com/cl-doc-systems&lt;/a&gt; include a build script and GitHub Action to update documentation on every commit!&lt;/p&gt;
</description>
            <pubDate>Thu, 31 Dec 2020 22:45:28 +0300</pubDate>
        </item>
        <item>
            <title>cl-api</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/12/0217-cl-api.html</link>
            <description>&lt;p&gt;This is a small and simple documentation builder. It was &lt;a href=&quot;https://github.com/quicklisp/quicklisp-projects/commit/e8c65442bbbfdfc0019f73513c8b15a04d134a4c&quot;&gt;removed from Quicklisp&lt;/a&gt; in 2014 because this project is SBCL only, but I&apos;ve added it to the &lt;a href=&quot;https://ultralisp.org/&quot;&gt;Ultralisp&lt;/a&gt; and you can test it after upgrade to the latest version.&lt;/p&gt;
&lt;p&gt;CL-API is suitable for building a reference for third-party libraries if they don&apos;t have their own documentation. But lack of ability to process handwritten chapters and work with package inferred systems, make it unusable for 40ants projects.&lt;/p&gt;
&lt;p&gt;As always, I&apos;ve created a template repository for you.&lt;/p&gt;
&lt;p&gt;Here is an example project&apos;s documentation built with CL-API:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cl-doc-systems.github.io/cl-api/&quot;&gt;https://cl-doc-systems.github.io/cl-api/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Use this template if you are making a small library which needs autogenerated API reference.&lt;/p&gt;
&lt;p&gt;Also, you&apos;ll find a &quot;Pros &amp; Cons&quot; section in the README:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cl-doc-systems/cl-api&quot;&gt;https://github.com/cl-doc-systems/cl-api&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here you will find template projects for other documentation systems.&lt;/p&gt;
&lt;p&gt;Choose what is more suite your needs:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cl-doc-systems&quot;&gt;https://github.com/cl-doc-systems&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Sat, 26 Dec 2020 22:04:59 +0300</pubDate>
        </item>
        <item>
            <title>eazy-documentation</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/12/0216-eazy-documentation.html</link>
            <description>&lt;p&gt;This is yet another documentation generator for Common Lisp, built by &lt;a href=&quot;https://twitter.com/guicho271828&quot;&gt;Masataro Asai&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Its unique feature is the documentation processor which is able to extract docstring from nonstandard Lisp forms. Also, it supports all markups, supported by &lt;a href=&quot;https://pandoc.org/&quot;&gt;Pandoc&lt;/a&gt; and can be used to generate documentation from any folder.&lt;/p&gt;
&lt;p&gt;You&apos;ll find more &lt;a href=&quot;https://cl-doc-systems.github.io/eazy-documentation/#doc/source/1%20pros-n-cons.rst&quot;&gt;pros and cons&lt;/a&gt; in the &lt;a href=&quot;https://github.com/cl-doc-systems/eazy-documentation&quot;&gt;template repository&lt;/a&gt; I&apos;ve prepared for you.&lt;/p&gt;
&lt;p&gt;Despite many cool features, I have these stoppers for using Eazy Documentation for my own projects:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;it is hard to control sections ordering;&lt;/li&gt;&lt;li&gt;there is no helper for cross-referencing symbols.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://cl-doc-systems.github.io/mgl-pax/&quot;&gt;MGL-PAX&lt;/a&gt;, reviewed recently is still my favourite.&lt;/p&gt;
&lt;p&gt;But Eazy Documentation still can be useful when:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;the system is small;&lt;/li&gt;&lt;li&gt;you just have a number of RST/Markdown/other files and want to make a   site;&lt;/li&gt;&lt;li&gt;you want to build a doc for a third-party library. It can build a doc   for any ASDF system.&lt;/li&gt;&lt;/ul&gt;
</description>
            <pubDate>Sun, 20 Dec 2020 00:59:54 +0300</pubDate>
        </item>
        <item>
            <title>cl-gendoc</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/12/0215-cl-gendoc.html</link>
            <description>&lt;p&gt;This is yet another CL documentation generator by Ryan Pavlik. It&apos;s interesting features are:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Markdown support out of the box.&lt;/li&gt;&lt;li&gt;New markups can be easily added.&lt;/li&gt;&lt;li&gt;Code from snippets can be linked to CLHS.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;As always, I&apos;ve prepared an example project for you:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cl-doc-systems.github.io/cl-gendoc/&quot;&gt;https://cl-doc-systems.github.io/cl-gendoc/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You&apos;ll find there a full list of &lt;code&gt;cl-gendoc&lt;/code&gt;&apos;s pros and cons.&lt;/p&gt;
&lt;p&gt;Here is a short example of library documentation builder. It includes a few markdown sections and an autogenerated API spec for two packages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;(defun build ()
  (let ((output-filename &amp;quot;docs/build/index.html&amp;quot;))
    (ensure-directories-exist output-filename)
    (gendoc:gendoc (:output-filename output-filename
                    :css &amp;quot;simple.css&amp;quot;)
      (:markdown-file &amp;quot;docs/source/index.md&amp;quot;)
      (:markdown-file &amp;quot;docs/source/pros-and-cons.md&amp;quot;)
      (:markdown-file &amp;quot;docs/source/handwritten.md&amp;quot;)
      (:markdown-file &amp;quot;docs/source/reference.md&amp;quot;)
      (:apiref :example/app
               :example/utils))))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;cl-gendoc&lt;/code&gt; has an interesting macro &lt;code&gt;define-gendoc-load-op&lt;/code&gt;. It forces documentation build after the &lt;code&gt;asdf:load-system&lt;/code&gt; call. Here is how it can be used:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;(defsystem example-docs
  :class :package-inferred-system
  :defsystem-depends-on (&amp;quot;cl-gendoc&amp;quot;)
  :pathname &amp;quot;docs/scripts/&amp;quot;
  :depends-on (&amp;quot;example-docs/builder&amp;quot;))

(gendoc:define-gendoc-load-op :example-docs
                              :example-docs/builder &amp;#039;build)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The macro call will expand into:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;(progn
 (defmethod asdf/action:perform :after ((o asdf/lisp-action:load-op) 
                                        (c (eql (asdf/system:find-system
                                                 :example-docs))))
   (let ((fn
          (find-symbol (symbol-name &amp;#039;build)
                       (find-package :example-docs/builder))))
     (funcall gendoc::fn)))

 ;; This method makes ASDF think that load-system wasn&amp;#039;t successful
 ;; and subsequent call will build documentation again.
 (defmethod asdf/action:operation-done-p ((o asdf/lisp-action:load-op) 
                                          (c (eql (asdf/system:find-system 
                                                   :example-docs))))
   nil))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Personally, I&apos;m don&apos;t like this hack. But I&apos;m sure there should be the more correct way to use &lt;code&gt;asdf:make&lt;/code&gt; to build docs. If you know how to do this, please, let me know in the comments.&lt;/p&gt;
</description>
            <pubDate>Sat, 12 Dec 2020 23:59:43 +0300</pubDate>
        </item>
        <item>
            <title>codex</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/12/0214-codex.html</link>
            <description>&lt;p&gt;This is a documentation generator by Fernando Boretti.&lt;/p&gt;
&lt;p&gt;It is built for extensibility and uses CommonDoc as an internal format for document representation and manipulation.&lt;/p&gt;
&lt;p&gt;Another interesting feature is a custom markup language Scriba (reviewed in &lt;a href=&quot;https://40ants.com/lisp-project-of-the-day/2020/09/0178-scriba.html&quot;&gt;post #0178&lt;/a&gt;). Actually, Codex supports any number of markup languages, you just need to write a parser from this markup into CommonDoc.&lt;/p&gt;
&lt;p&gt;The sad part is that there is no support for cross-referencing and there are a number of bugs :(&lt;/p&gt;
&lt;p&gt;As always, I&apos;ve created a template project for you, demonstrating how to use Codex to document a simple Common Lisp library:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cl-doc-systems/codex&quot;&gt;https://github.com/cl-doc-systems/codex&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Read about other pros and cons on this page:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cl-doc-systems.github.io/codex/pros-&amp;-cons-of-codex.html&quot;&gt;https://cl-doc-systems.github.io/codex/pros-&amp;-cons-of-codex.html&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Thu, 03 Dec 2020 22:02:34 +0300</pubDate>
        </item>
        <item>
            <title>mgl-pax</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/11/0213-mgl-pax.html</link>
            <description>&lt;p&gt;This is a very cool documentation generator for Common Lisp projects.&lt;/p&gt;
&lt;p&gt;The most interesting features are:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Emacs/SLIME integration.&lt;/li&gt;&lt;li&gt;Ability to generate Markdown.&lt;/li&gt;&lt;li&gt;API to add new entity types.&lt;/li&gt;&lt;li&gt;Linking to the sources on the GitHub.&lt;/li&gt;&lt;li&gt;Docstrings deindentation.&lt;/li&gt;&lt;li&gt;Generation docs for multiple ASDF systems with cross-referencing.&lt;/li&gt;&lt;li&gt;Auto-export of documented symbols.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Some cons:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;The recommended way to mix documentation section with code leads to   the runtime dependency from PAX and all it&apos;s dependencies. But you   might define documentation as a separate ASDF system.&lt;/li&gt;&lt;li&gt;It is inconvenient to write Markdown in docstrings. Is there any way   to teach Emacs to use markdown minor mode for documentation strings?&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;There are more pros and cons. All of them are listed in the &lt;a href=&quot;https://cl-doc-systems.github.io/mgl-pax/#x-28EXAMPLE-DOCS-2FDOCS-3A-40PROS-N-CONS-20MGL-PAX-3ASECTION-29&quot;&gt;example project&lt;/a&gt;. It is up and ready to be cloned. Use it as a template for your own Common Lisp library with great documentation!&lt;/p&gt;
&lt;p&gt;You&apos;ll find all such templates in this GitHub organization:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cl-doc-systems&quot;&gt;https://github.com/cl-doc-systems&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I have plans to review a few other documentation builders, but MGL-PAX is my favourite so far.&lt;/p&gt;
</description>
            <pubDate>Mon, 30 Nov 2020 00:43:06 +0300</pubDate>
        </item>
        <item>
            <title>staple</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/11/0212-staple.html</link>
            <description>&lt;p&gt;Today we&apos;ll look at &lt;a href=&quot;https://twitter.com/Shinmera&quot;&gt;@Shinmera&lt;/a&gt;&apos;s documentation system called &lt;a href=&quot;https://shinmera.github.io/staple/&quot;&gt;Staple&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As always, I&apos;ve created &lt;a href=&quot;https://github.com/cl-doc-systems/staple&quot;&gt;the skeleton project&lt;/a&gt; for you.&lt;/p&gt;
&lt;p&gt;But I must warn you. This skeleton is almost unusable, because of a few problems.&lt;/p&gt;
&lt;p&gt;The first problem is that I wasn&apos;t able to make markdown work for the docstrings. When I do setup like suggests Staple documentation, it does not see all package of my system.&lt;/p&gt;
&lt;p&gt;The second problem is that for some reason it works badly with my simple example system. It shows on the index page multiple equal links to the Example system.&lt;/p&gt;
&lt;p&gt;Probably both problems are related to the ASDF system type. I&apos;m using package inferred systems.&lt;/p&gt;
&lt;p&gt;Also, the Staple&apos;s error messages a complete mess. It is not possible to figure out the origin of a warning. The output looks like that:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;text&apos;&gt;Scan was called 76 times.
Warning: could not find hyperspec map file. Adjust the path at the top of clhs-lookup.lisp to get links to the HyperSpec.
Scan was called 384 times.
Scan was called 116 times.
Scan was called 287 times.
Scan was called 94 times.
Scan was called 2005 times.
Scan was called 162 times.
Scan was called 162 times.
Scan was called 186 times.
Scan was called 397 times.
Scan was called 221 times.
Scan was called 502 times.
Scan was called 134 times.
Scan was called 130 times.
Scan was called 395 times.
Scan was called 1453 times.
WARN: Error during code markup: Invalid function name: STR:DOWNCASE
WARN: Error during code markup: Symbol name must not end with a package marker (the : character).
Scan was called 2782 times.
WARN: Error during code markup: Unquote not inside backquote.
Scan was called 95 times.
Scan was called 2019 times.
Scan was called 4518 times.
Scan was called 2670 times.
Scan was called 2209 times.
WARN: Error during code markup: A token consisting solely of multiple dots is illegal.
WARN: Error during code markup: Invalid function name: DOCPARSER:PARSE
WARN: Error during code markup: The character &amp;lt; is not a valid sub-character for the # dispatch macro.
WARN: Error during code markup: The character &amp;lt; is not a valid sub-character for the # dispatch macro.
WARN: Error during code markup: Symbol name must not end with a package marker (the : character).
WARN: Error during code markup: Invalid function name: 4
WARN: Error during code markup: Invalid function name: STAPLE-SERVER:START
WARN: Error during code markup: Invalid function name: STAPLE-SERVER:STOP
WARN: Error during code markup: Invalid function name: LQUERY-TEST:RUN
WARN: Error during code markup: Invalid function name: 1
WARN: Error during code markup: Symbol name without any escapes must not consist solely of package markers (: characters).
WARN: Error during code markup: The value
                                  NIL
                                is not of type
                                  CHARACTER
WARN: Error during code markup: The value
                                  NIL
                                is not of type
                                  CHARACTER
WARN: Error during code markup: While reading backquote, expected an object when input ended.
WARN: Error during code markup: While reading backquote, expected an object when input ended.
WARN: Error during code markup: The value
                                  NIL
                                is not of type
                                  CHARACTER
WARN: Error during code markup: Symbol name without any escapes must not consist solely of package markers (: characters).
WARN: Error during code markup: If a symbol token contains two package markers, they must be adjacent as in package::symbol.
WARN: Error during code markup: The value
                                  NIL
                                is not of type
                                  CHARACTER
WARN: Error during code markup: While reading symbol, expected the character | when input ended.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Another hard thing is customization. Seems Staple was built for maximum flexibility and sometimes it is not obvious how to do such simple thing like adding yet another markdown page to the output.&lt;/p&gt;
&lt;p&gt;Now to the good news :)&lt;/p&gt;
&lt;p&gt;As I said Staple is very flexible. It uses CLOS and generic functions almost everywhere and you can extend it in a number ways. For example, you can add support for your own markup language.&lt;/p&gt;
&lt;p&gt;There is also a unique feature: Staple automatically links every function documentation to its source on the GitHub:&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;max-width: 100%&quot; src=&quot;../../media/0212/gh-link.png&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Documentation for &lt;a href=&quot;https://twitter.com/Shinmera&quot;&gt;@Shinmera&lt;/a&gt;&apos;s libraries looks really good. Take look to the Radiance, for example:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://shirakumo.github.io/radiance/&quot;&gt;https://shirakumo.github.io/radiance/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Probably Staple just needs more polishing to become a great documentation system for Common Lisp libraries?&lt;/p&gt;
&lt;p&gt;For now &lt;a href=&quot;https://40ants.com/lisp-project-of-the-day/2020/11/0211-coo.html&quot;&gt;Coo&lt;/a&gt; is my favourite. But in the next week or two, we&apos;ll look at a few other Common Lisp documentation systems.&lt;/p&gt;
&lt;p&gt;Seems documentation building works quite unstable and sometimes does not build some pages where is running on the CI :(&lt;/p&gt;
</description>
            <pubDate>Tue, 10 Nov 2020 01:10:25 +0300</pubDate>
        </item>
        <item>
            <title>coo</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/11/0211-coo.html</link>
            <description>&lt;p&gt;This system is not in the Quicklisp yet. You can install it from the &lt;a href=&quot;https://github.com/fisxoj/coo&quot;&gt;GitHub&lt;/a&gt; or &lt;a href=&quot;https://ultralisp.org&quot;&gt;Ultralisp.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I think to make it a tradition – creating a ready to use project skeletons.&lt;/p&gt;
&lt;p&gt;Here is one which uses Coo:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/cl-doc-systems/coo/&quot;&gt;https://github.com/cl-doc-systems/coo/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here is how it&apos;s rendered documentation looks like.&lt;/p&gt;
&lt;p&gt;Read this doc to learn more about the pros and cons of this documentation system:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cl-doc-systems.github.io/coo/&quot;&gt;https://cl-doc-systems.github.io/coo/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here I want to highlight only a few moments.&lt;/p&gt;
&lt;p&gt;The system has a huge potential for improvement. There are some GitHub issues to work on. I&apos;ve already sent my pull-request to add support of ASDF package inferred systems:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/fisxoj/coo/pull/24&quot;&gt;https://github.com/fisxoj/coo/pull/24&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The two coolest features are:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Well-known markup format – Coo uses reStructured text.&lt;/li&gt;&lt;li&gt;It can be extended in Common Lisp.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Right now Coo is good for documenting small libraries which don&apos;t need for abstract chapters of documentation, but I see how it can be extended to render handwritten docs along with generated from docstrings!&lt;/p&gt;
</description>
            <pubDate>Fri, 06 Nov 2020 01:14:56 +0300</pubDate>
        </item>
        <item>
            <title>sphinxcontrib-cldomain</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/11/0210-sphinxcontrib-cldomain.html</link>
            <description>&lt;p&gt;This is an add-on to the &lt;a href=&quot;https://www.sphinx-doc.org/en/master/&quot;&gt;Sphinx&lt;/a&gt; documentation system which allows using of information about Common Lisp packages in the documentation.&lt;/p&gt;
&lt;p&gt;Initially, Sphinx was created for Python&apos;s documentation and now it is widely used not only for python libraries but also for many other languages.&lt;/p&gt;
&lt;p&gt;Sphinx uses reStructured text markup language which is extensible. You can write your own extensions in Python to introduce new building blocks, called &quot;roles&quot;.&lt;/p&gt;
&lt;p&gt;sphinxcontrib-cldomain consists of two parts. The first part is a python extension to the Sphinx which adds an ability to render documentation for CL functions, methods and classes. The second - a command-line docstring extractor, written in CL.&lt;/p&gt;
&lt;p&gt;Initially, cldomain was created by Russell Sim, but at some moment I&apos;ve &lt;a href=&quot;https://github.com/40ants/sphinxcontrib-cldomain&quot;&gt;forked&lt;/a&gt; the repository to port it to the newer Sphinx, Python3 and Roswell.&lt;/p&gt;
&lt;p&gt;The coolest feature of the &lt;code&gt;cldomain&lt;/code&gt; is its ability to mix handwritten documentation with docstring. The second - cross-referencing. You can link between different docstrings and chapters of the documentation.&lt;/p&gt;
&lt;p&gt;Today I will not show you any code snippets. Instead, I&apos;ve created an example repository with a simple Common Lisp system and documentation:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://cl-doc-systems.github.io/sphinxcontrib-cldomain/&quot;&gt;https://cl-doc-systems.github.io/sphinxcontrib-cldomain/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This example includes a GitHub workflow to update the documentation on a push to the main branch and can be used as a skeleton for you own libraries.&lt;/p&gt;
&lt;p&gt;The main thing I dislike in Sphinx and cldomain is the Python :( Other cons are the complexity of the markup and toolchain setup.&lt;/p&gt;
&lt;p&gt;In the next few posts, I&apos;ll review a few other documentation tools for Common Lisp and try to figure out if they can replace Sphinx for me.&lt;/p&gt;
&lt;p&gt;I think we as CL community must concentrate our efforts to improve the documentation level of our software and choosing the best setup which can be recommended for everybody is the key.&lt;/p&gt;
</description>
            <pubDate>Sun, 01 Nov 2020 03:43:43 +0300</pubDate>
        </item>
        <item>
            <title>cl-pdf</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/10/0209-cl-pdf.html</link>
            <description>&lt;p&gt;This is the library for PDF generation and parsing.&lt;/p&gt;
&lt;p&gt;Today I&apos;m too lazy to provided step by step examples, but I have a real task to do with this library.&lt;/p&gt;
&lt;p&gt;Some time ago I&apos;ve read the &lt;a href=&quot;https://waitbutwhy.com/2014/05/life-weeks.html&quot;&gt;article about productivity&lt;/a&gt; which recommended to print a &quot;life calendar&quot;. This calendar should remind you: &quot;The life is limited and the time&apos;s price is high.&quot;&lt;/p&gt;
&lt;p&gt;The calendar is a grid where every box is one week of you life. The article suggested to buy a poster with the calendar, but I don&apos;t want to wait for a parcel with the poster! I want to print it now!&lt;/p&gt;
&lt;p&gt;And here is where cl-pdf comes on the scene!&lt;/p&gt;
&lt;p&gt;I wrote this simple function to generate the poster of A1 format:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;(defun render (&amp;amp;optional (filename &amp;quot;life.pdf&amp;quot;))
  (flet ((to-ppt (size-in-mm)
           (/ size-in-mm 1/72 25.4)))
    (let* ((width (to-ppt 594))       ;; This is A1 page size in mm
           (height (to-ppt 841))
           (margin-top (to-ppt 70))
           (margin-bottom (to-ppt 30))
           (span  (to-ppt 2))
           (year-weeks 52)
           (years 90)
           (box-size (/ (- (- height (+ margin-top margin-bottom))
                            (* span (1- years)))
                        years))
           (boxes-width (+ (* box-size year-weeks)
                            (* span (1- year-weeks))))
           (boxes-height (+ (* box-size years)
                             (* span (1- years))))
           ;; horizontal margin depends on box size,
           ;; because we need to center them
           (margin-h (/ (- width boxes-width)
                        2))
           (box-radius (/ box-size 3))
           (helvetica (pdf:get-font &amp;quot;Helvetica&amp;quot;)))
      (pdf:with-document ()
        (pdf:with-page (:bounds (rutils:vec 0 0 width height))
          ;; For debug
          ;; (pdf:rectangle margin-h margin-bottom
          ;;                boxes-width
          ;;                boxes-height
          ;;                :radius box-radius)
          (loop for year from 0 below years
                do (loop for week from 0 below year-weeks
                         for x = (+ margin-h (* week (+ box-size span)))
                         for y = (+ margin-bottom (* year (+ box-size span)))
                         do (pdf:rectangle x y box-size box-size :radius box-radius)))
          
          ;; The title
          (pdf:draw-centered-text
           (/ width 2)
           (+ margin-bottom
               boxes-height
               ;; space between text and boxes in mm
               (to-ppt 15))
           &amp;quot;LIFE CALENDAR&amp;quot;
           helvetica
           ;; font-size in mm
           (to-ppt 30))

          ;; Labels for weeks
          (let ((font-size
                  ;; We want labels to be slightly smaller than boxes
                  (* box-size 2/3)))
            (pdf:draw-right-text
             (+ margin-h
                 (/ box-size 4))
             (+ margin-bottom
                 boxes-height
                 ;; space between text and boxes in mm
                 (to-ppt 10))
             &amp;quot;Weeks of the year&amp;quot;
             helvetica
             font-size)
            
            (loop for week below year-weeks
                  do (pdf:draw-centered-text
                      (+ margin-h
                          (/ box-size 2)
                          (* week (+ box-size span)))
                      (+ margin-bottom
                          boxes-height
                          ;; space between text and boxes in mm
                          (to-ppt 3))
                      (rutils:fmt &amp;quot;~A&amp;quot; (1+ week))
                      helvetica
                      font-size))

            ;; Labels for years
            (pdf:with-saved-state
              (pdf:translate
               (- margin-h
                   (to-ppt 10))
               (- (+ margin-bottom
                      boxes-height)
                   (/ box-size 4)))
              (pdf:rotate 90)
              (pdf:draw-left-text
               0 0
               &amp;quot;Years of your life&amp;quot;
               helvetica
               font-size))
            
            (loop for year below years
                  do (pdf:draw-left-text
                      (- margin-h
                          ;; space between text and boxes in mm
                          (to-ppt 3))
                      (+ margin-bottom
                          (/ box-size 4)
                          (* year (+ box-size span)))
                      (rutils:fmt &amp;quot;~A&amp;quot; (- years year))
                      helvetica
                      font-size))

            ;; The Question.
            (pdf:draw-left-text
             (- width margin-h)
             (- margin-bottom
                 (to-ppt 10))
             &amp;quot;Is this the End?&amp;quot;
             helvetica
             (* font-size 2))
            
            (pdf:close-and-stroke)))
        (pdf:write-document filename)))))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here is how result will look like:&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;max-width: 100%&quot; src=&quot;../../media/0209/life.png&quot;/&gt;&lt;/p&gt;
&lt;p&gt;The PDF can be &lt;a href=&quot;https://40ants.com/lisp-project-of-the-day/media/0209/life.pdf&quot;&gt;downloaded here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This program demonstrates a few features of cl-pdf:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;ability to set page size;&lt;/li&gt;&lt;li&gt;text drawing and rotation;&lt;/li&gt;&lt;li&gt;font manipulation.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;There are a lot more features but all of them aren&apos;t documented, only &lt;a href=&quot;https://github.com/mbattyani/cl-pdf/tree/master/examples&quot;&gt;several examples&lt;/a&gt; :(&lt;/p&gt;
&lt;p&gt;GitHub &lt;a href=&quot;https://github.com/mbattyani/cl-pdf/network&quot;&gt;shows 4 forks&lt;/a&gt; with some patches. And some of them are turned into a pull-request, but maintainer is inactive on the GitHub since 2019 :(&lt;/p&gt;
</description>
            <pubDate>Wed, 28 Oct 2020 23:49:29 +0300</pubDate>
        </item>
        <item>
            <title>cl-async-await</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/10/0208-cl-async-await.html</link>
            <description>&lt;p&gt;&lt;a href=&quot;https://github.com/j3pic/cl-async-await&quot;&gt;This library&lt;/a&gt; implements the &lt;a href=&quot;https://en.wikipedia.org/wiki/Futures_and_promises&quot;&gt;async/await abstraction&lt;/a&gt; to make it easier to write parallel programs.&lt;/p&gt;
&lt;p&gt;Now we&apos;ll turn &quot;dexador&quot; http library calls into async and will see if we can parallel 50 requests to the site which response in 5 seconds.&lt;/p&gt;
&lt;p&gt;To create a function which can return a delayed result, a &quot;promise&quot;, we have to use &lt;code&gt;cl-async-await:defun-async&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (cl-async-await:defun-async http-get (url &amp;amp;rest args)
             (apply #&amp;#039;dexador:get url args))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now let&apos;s call this function. When called it returns a &quot;promise&quot; object not the real response from the site:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (http-get &amp;quot;https://httpbin.org/delay/5&amp;quot;)
#&amp;lt;CL-ASYNC-AWAIT:PROMISE Not awaited&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can retrieve the real result, using &lt;code&gt;cl-async-await:await&lt;/code&gt; function:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (cl-async-await:await *)
&amp;quot;{
  \&amp;quot;args\&amp;quot;: {}, 
  \&amp;quot;data\&amp;quot;: \&amp;quot;\&amp;quot;, 
  \&amp;quot;files\&amp;quot;: {}, 
  \&amp;quot;form\&amp;quot;: {}, 
  \&amp;quot;headers\&amp;quot;: {
    \&amp;quot;Accept\&amp;quot;: \&amp;quot;*/*\&amp;quot;, 
    \&amp;quot;Content-Length\&amp;quot;: \&amp;quot;0\&amp;quot;, 
    \&amp;quot;Host\&amp;quot;: \&amp;quot;httpbin.org\&amp;quot;, 
    \&amp;quot;User-Agent\&amp;quot;: \&amp;quot;Dexador/0.9.14 (SBCL 2.0.8); Darwin; 19.5.0\&amp;quot;, 
    \&amp;quot;X-Amzn-Trace-Id\&amp;quot;: \&amp;quot;Root=1-5f9732d6-148ee9a305fab66c26a2dbfd\&amp;quot;
  }, 
  \&amp;quot;origin\&amp;quot;: \&amp;quot;188.170.77.131\&amp;quot;, 
  \&amp;quot;url\&amp;quot;: \&amp;quot;https://httpbin.org/delay/5\&amp;quot;
}
&amp;quot;
200 (8 bits, #xC8, #o310, #b11001000)
#&amp;lt;HASH-TABLE :TEST EQUAL :COUNT 7 {1002987DE3}&amp;gt;
#&amp;lt;QURI.URI.HTTP:URI-HTTPS https://httpbin.org/delay/5&amp;gt;
#&amp;lt;CL+SSL::SSL-STREAM for #&amp;lt;FD-STREAM for &amp;quot;socket 192.168.43.216:49762, peer: 35.170.225.136:443&amp;quot; {10085B0BF3}&amp;gt;&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we look a the promise object again, we&apos;ll see it has a state now:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; **
#&amp;lt;CL-ASYNC-AWAIT:PROMISE (VALUES {
  &amp;quot;args&amp;quot;: {}, 
  &amp;quot;data&amp;quot;: &amp;quot;&amp;quot;, 
  &amp;quot;files&amp;quot;: {}, 
  &amp;quot;form&amp;quot;: {}, 
  &amp;quot;headers&amp;quot;: {
    &amp;quot;Accept&amp;quot;: &amp;quot;*/*&amp;quot;, 
    &amp;quot;Content-Length&amp;quot;: &amp;quot;0&amp;quot;, 
    &amp;quot;Host&amp;quot;: &amp;quot;httpbin.org&amp;quot;, 
    &amp;quot;User-Agent&amp;quot;: &amp;quot;Dexador/0.9.14 (SBCL 2.0.8); Darwin; 19.5.0&amp;quot;, 
    &amp;quot;X-Amzn-Trace-Id&amp;quot;: &amp;quot;Root=1-5f9732d6-148ee9a305fab66c26a2dbfd&amp;quot;
  }, 
  &amp;quot;origin&amp;quot;: &amp;quot;188.170.77.131&amp;quot;, 
  &amp;quot;url&amp;quot;: &amp;quot;https://httpbin.org/delay/5&amp;quot;
}

  200 #&amp;lt;HASH-TABLE :TEST EQUAL :COUNT 7 {1002987DE3}&amp;gt;
  https://httpbin.org/delay/5
  #&amp;lt;SSL-STREAM for #&amp;lt;FD-STREAM for &amp;quot;socket 192.168.43.216:49762, peer: 35.170.225.136:443&amp;quot; {10085B0BF3}&amp;gt;&amp;gt;) &amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ok, it is time to see if we can retrieve results from this site in parallel. To make it easier to test speed, I&apos;ll wrap all code into the separate function.&lt;/p&gt;
&lt;p&gt;The function returns the total number of bytes in all 50 responses:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (defun do-the-test ()
             (let ((promises
                     (loop repeat 50
                           collect (http-get &amp;quot;https://httpbin.org/delay/5&amp;quot;
                                             :use-connection-pool nil
                                             :keep-alive nil))))
               ;; Now we have to fetch results from our promises.
               (loop for promise in promises
                     for response = (cl-async-await:await
                                     promise)
                     summing (length response))))

POFTHEDAY&amp;gt; (time (do-the-test))
Evaluation took:
  6.509 seconds of real time
  2.496912 seconds of total run time (1.672766 user, 0.824146 system)
  38.36% CPU
  14,372,854,434 processor cycles
  1,519,664 bytes consed
  
18300&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see, the function returns in 6.5 seconds instead of 250 seconds! This means cl-async-await works!&lt;/p&gt;
&lt;p&gt;The only problem I found was this concurrency issue:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/j3pic/cl-async-await/issues/3&quot;&gt;https://github.com/j3pic/cl-async-await/issues/3&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But probably it is only related to Dexador.&lt;/p&gt;
</description>
            <pubDate>Mon, 26 Oct 2020 23:48:09 +0300</pubDate>
        </item>
        <item>
            <title>parseq</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/10/0207-parseq.html</link>
            <description>&lt;p&gt;With this library, you can write parsers to process strings, lists and binary data!&lt;/p&gt;
&lt;p&gt;Let&apos;s take a look at one of the examples. It is a parser for the dates from &lt;a href=&quot;https://tools.ietf.org/html/rfc5322#section-3.3&quot;&gt;RFC 5322&lt;/a&gt;. This format is used in email messages:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Thu, 13 Jul 2017 13:28:03 +0200&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Parser consist of rules, combined in different ways. We&apos;ll go through the parser&apos;s parts one by one.&lt;/p&gt;
&lt;p&gt;This simple rule matches one space character:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (parseq:defrule FWS ()
               #\space)

;; It matches if string contains one space
POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;FWS
                          &amp;quot; &amp;quot;)
#\ 
T

;; But not on string from many spaces:
POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;FWS
                          &amp;quot;   &amp;quot;)
NIL
NIL

;; And of cause not on some other string
POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;FWS
                          &amp;quot;foo&amp;quot;)
NIL
NIL&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The next rule we need is the rule to parse hours, minutes and seconds. These parts have two digits and we&apos;ll use &lt;code&gt;rep&lt;/code&gt; expression to specify how many digits matches the rule:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (parseq:defrule hour ()
               (rep 2 digit))

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;hour
                          &amp;quot;15&amp;quot;)
(#\1 #\5)
T&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;See, this rule returns digits as the list! But to make it useful, we need the integer. Parseq rules support different kinds of transformations. They can are optional and can be specified like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;;; This transformation will return as the string instead of list:
POFTHEDAY&amp;gt; (parseq:defrule hour ()
               (rep 2 digit)
             (:string))

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;hour
                          &amp;quot;15&amp;quot;)
&amp;quot;15&amp;quot;
T

;; Now we&amp;#039;ll add a transformation from string to integer:
POFTHEDAY&amp;gt; (parseq:defrule hour ()
               (rep 2 digit)
             (:string)
             (:function #&amp;#039;parse-integer))

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;hour
                          &amp;quot;15&amp;quot;)
15 (4 bits, #xF, #o17, #b1111)
T&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We&apos;ll define the &lt;code&gt;minute&lt;/code&gt; and &lt;code&gt;second&lt;/code&gt; rules the same way.&lt;/p&gt;
&lt;p&gt;The next rule matches the abbreviated day of the week. It combines other rules or terms using &lt;code&gt;or&lt;/code&gt; expression:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (parseq:defrule day-of-week ()
               (or &amp;quot;Mon&amp;quot; &amp;quot;Tue&amp;quot; &amp;quot;Wed&amp;quot;
                   &amp;quot;Thu&amp;quot; &amp;quot;Fri&amp;quot; &amp;quot;Sat&amp;quot;
                   &amp;quot;Sun&amp;quot;))

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;day-of-week
                          &amp;quot;Friday&amp;quot;)
NIL
NIL

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;day-of-week
                          &amp;quot;Fri&amp;quot;)
&amp;quot;Fri&amp;quot;
T

;; The same way we define a rule for month abbrefiation
POFTHEDAY&amp;gt; (parseq:defrule month ()
               (or &amp;quot;Jan&amp;quot; &amp;quot;Feb&amp;quot; &amp;quot;Mar&amp;quot; &amp;quot;Apr&amp;quot;
                   &amp;quot;May&amp;quot; &amp;quot;Jun&amp;quot; &amp;quot;Jul&amp;quot; &amp;quot;Aug&amp;quot;
                   &amp;quot;Sep&amp;quot; &amp;quot;Oct&amp;quot; &amp;quot;Nov&amp;quot; &amp;quot;Dec&amp;quot;))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;A little bit complex rule is used for matching timezone. Timezone is a string from 4 digits prefixed by plus or minus sign. We&apos;ll combine this knowledge using &lt;code&gt;or/and&lt;/code&gt; expressions and will use option &lt;code&gt;:string&lt;/code&gt; to get results as a single string:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (parseq:defrule zone ()
               (and (or &amp;quot;+&amp;quot; &amp;quot;-&amp;quot;)
                    (rep 4 digit))
             (:string))

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;zone
                          &amp;quot;0300&amp;quot;)
NIL
NIL

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;zone
                          &amp;quot;+0300&amp;quot;)
&amp;quot;+0300&amp;quot;
T

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;zone
                          &amp;quot;-0300&amp;quot;)
&amp;quot;-0300&amp;quot;
T&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now let&apos;s return to the time of day parsing. According to the RFC, seconds part is optional. Parseq has an expression &lt;code&gt;?&lt;/code&gt; to match optional rules.&lt;/p&gt;
&lt;p&gt;Here is how a rule matching the time of day will look like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (parseq:defrule time-of-day ()
               (and hour
                    &amp;quot;:&amp;quot;
                    minute
                    (? (and &amp;quot;:&amp;quot; second))))

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;time-of-day
                          &amp;quot;10:31:05&amp;quot;)
(10 &amp;quot;:&amp;quot; 31 (&amp;quot;:&amp;quot; 5))
T&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To make the rule return only digits we have to use &lt;code&gt;:choose&lt;/code&gt; transform. Choose extracts from results by index. You can specify index as an integer or as a list if you need to extract the value from the nested list:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (parseq:defrule time-of-day ()
               (and hour
                    &amp;quot;:&amp;quot;
                    minute
                    (? (and &amp;quot;:&amp;quot; second)))
             (:choose 0 2 &amp;#039;(3 1)))

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;time-of-day
                          &amp;quot;10:31:05&amp;quot;)
(10 31 5)

;; Seconds are optional because of ? expression:
POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;time-of-day
                          &amp;quot;10:31&amp;quot;)
(10 31 NIL)
T

;; This (:choose 0 2 &amp;#039;(3 1)) is equivalent to:
POFTHEDAY&amp;gt; (let ((r &amp;#039;(10 &amp;quot;:&amp;quot; 31 (&amp;quot;:&amp;quot; 5))))
             (list (elt r 0)
                   (elt r 2)
                   (elt (elt r 3)
                        1)))
(10 31 5)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Another interesting transformation rule is &lt;code&gt;:flatten&lt;/code&gt;. It is used to &quot;streamline&quot; result having nested structure and used in this rule which matches both time of day and timezone:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;;; Without flatten we&amp;#039;ll get nested lists:
POFTHEDAY&amp;gt; (parseq:defrule time ()
               (and time-of-day FWS zone)
             (:choose 0 2))

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;time
                          &amp;quot;10:31 +0300&amp;quot;)
((10 31 NIL) &amp;quot;+0300&amp;quot;)

POFTHEDAY&amp;gt; (parseq:defrule time ()
               (and time-of-day FWS zone)
             (:choose 0 2)
             (:flatten))

;; Pay attention, :flatten removes nils:
POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;time
                          &amp;quot;10:31 +0300&amp;quot;)
(10 31 &amp;quot;+0300&amp;quot;)
T&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now, knowing how rules are combined and data is transformed, you will be able to read rest rules yourself:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (parseq:defrule day ()
               (and (? FWS)
                    (rep (1 2) digit)
                    FWS)
             (:choose 1)
             (:string)
             (:function #&amp;#039;parse-integer))

POFTHEDAY&amp;gt; (parseq:defrule year ()
               (and FWS
                    (rep 4 digit)
                    FWS)
             (:choose 1)
             (:string)
             (:function #&amp;#039;parse-integer))

POFTHEDAY&amp;gt; (parseq:defrule date ()
               (and day month year))

(parseq:defrule date-time ()
    (and (? (and day-of-week &amp;quot;,&amp;quot;))
         date
         time)
  (:choose &amp;#039;(0 0) 1 2)
  (:flatten))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Another cool Parseq&apos;s feature is an ability to debug parser execution. Now I&apos;ll turn on this debug mode and parse a string:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (parseq:trace-rule &amp;#039;date-time :recursive t)

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;date-time
                          &amp;quot;Thu, 13 Jul 2017 13:28:03 +0200&amp;quot;)
1: DATE-TIME 0?
 2: DAY-OF-WEEK 0?
 2: DAY-OF-WEEK 0-3 -&amp;gt; &amp;quot;Thu&amp;quot;
 2: DATE 4?
  3: DAY 4?
   4: FWS 4?
   4: FWS 4-5 -&amp;gt; #\ 
   4: FWS 7?
   4: FWS 7-8 -&amp;gt; #\ 
  3: DAY 4-8 -&amp;gt; 13
  3: MONTH 8?
  3: MONTH 8-11 -&amp;gt; &amp;quot;Jul&amp;quot;
  3: YEAR 11?
   4: FWS 11?
   4: FWS 11-12 -&amp;gt; #\ 
   4: FWS 16?
   4: FWS 16-17 -&amp;gt; #\ 
  3: YEAR 11-17 -&amp;gt; 2017
 2: DATE 4-17 -&amp;gt; (13 &amp;quot;Jul&amp;quot; 2017)
 2: TIME 17?
  3: TIME-OF-DAY 17?
   4: HOUR 17?
   4: HOUR 17-19 -&amp;gt; 13
   4: MINUTE 20?
   4: MINUTE 20-22 -&amp;gt; 28
   4: SECOND 23?
   4: SECOND 23-25 -&amp;gt; 3
  3: TIME-OF-DAY 17-25 -&amp;gt; (13 28 3)
  3: FWS 25?
  3: FWS 25-26 -&amp;gt; #\ 
  3: ZONE 26?
  3: ZONE 26-31 -&amp;gt; &amp;quot;+0200&amp;quot;
 2: TIME 17-31 -&amp;gt; (13 28 3 &amp;quot;+0200&amp;quot;)
1: DATE-TIME 0-31 -&amp;gt; (&amp;quot;Thu&amp;quot; 13 &amp;quot;Jul&amp;quot; 2017 13 28 3 &amp;quot;+0200&amp;quot;)

(&amp;quot;Thu&amp;quot; 13 &amp;quot;Jul&amp;quot; 2017 13 28 3 &amp;quot;+0200&amp;quot;)
T&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can improve this parser by using &lt;code&gt;:function&lt;/code&gt; transformation to return a &lt;code&gt;local-time:timestamp&lt;/code&gt;. First, let&apos;s redefine rule for matching the month and make it return the month number:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (parseq:defrule january  () &amp;quot;Jan&amp;quot; (:constant 1))
POFTHEDAY&amp;gt; (parseq:defrule february () &amp;quot;Feb&amp;quot; (:constant 2))
POFTHEDAY&amp;gt; (parseq:defrule march    () &amp;quot;Mar&amp;quot; (:constant 3))
POFTHEDAY&amp;gt; (parseq:defrule april    () &amp;quot;Apr&amp;quot; (:constant 4))
POFTHEDAY&amp;gt; (parseq:defrule may      () &amp;quot;May&amp;quot; (:constant 5))
POFTHEDAY&amp;gt; (parseq:defrule june     () &amp;quot;Jun&amp;quot; (:constant 6))
POFTHEDAY&amp;gt; (parseq:defrule july     () &amp;quot;Jul&amp;quot; (:constant 7))
POFTHEDAY&amp;gt; (parseq:defrule august   () &amp;quot;Aug&amp;quot; (:constant 8))
POFTHEDAY&amp;gt; (parseq:defrule september () &amp;quot;Sep&amp;quot; (:constant 9))
POFTHEDAY&amp;gt; (parseq:defrule october  () &amp;quot;Oct&amp;quot; (:constant 10))
POFTHEDAY&amp;gt; (parseq:defrule november () &amp;quot;Nov&amp;quot; (:constant 11))
POFTHEDAY&amp;gt; (parseq:defrule december () &amp;quot;Dec&amp;quot; (:constant 12))

POFTHEDAY&amp;gt; (parseq:defrule month ()
               (or january february march april
                   may june july august
                   september october november december))

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;month &amp;quot;Sep&amp;quot;)
9 (4 bits, #x9, #o11, #b1001)
T&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Next, we need to reimplement the rule matching a timezone to make it return &lt;code&gt;local-time:timezone&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;We&apos;ll be using an advanced technique of binding variables to pass value from one rule to another, because I want to store the timezone as a string and to parse it&apos;s hour and minute parts simultaneously.&lt;/p&gt;
&lt;p&gt;To accomplish this task, we have to divide or timezone matching rule into two. The first rule will match it as a string of sign and four digits. Then it will save the result into an external variable and exit with a nil result to give a chance to execute the second rule:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (parseq:defrule zone-as-str ()
               (and (or #\+ #\-)
                    (rep 4 digit))
             (:string)
             (:external zone-as-str)
             ;; Save the value into a variable:
             (:lambda (z)
               (setf zone-as-str z))
             ;; and just exit:
             (:test (z)
               (declare (ignore z))
               nil))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we&apos;ll redefine our &lt;code&gt;zone&lt;/code&gt; rule to call &lt;code&gt;zone-as-str&lt;/code&gt; first and then to parse the same text again, this time as hours and minutes. As the final step, it creates a &lt;code&gt;local-time:timezone&lt;/code&gt; object:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (parseq:defrule zone ()
               (or zone-as-str
                   (and (or #\+ #\-)
                        hour
                        minute))
             (:let zone-as-str)
             (:lambda (sign hour minute)
               (local-time::%make-simple-timezone
                zone-as-str
                zone-as-str
                ;; This is an offset in seconds:
                (+ (* (ecase sign
                        (#\+ 1)
                        (#\- -1))
                      hour
                      3600)
                   (* minute 60)))))

;; Here is the execution trace:
POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;zone
                          &amp;quot;+0300&amp;quot;)
1: ZONE 0?
 2: ZONE-AS-STR 0?
 2: ZONE-AS-STR -|
 2: HOUR 1?
 2: HOUR 1-3 -&amp;gt; 3
 2: MINUTE 3?
 2: MINUTE 3-5 -&amp;gt; 0
1: ZONE 0-5 -&amp;gt; #&amp;lt;LOCAL-TIME::TIMEZONE +0300&amp;gt;
#&amp;lt;LOCAL-TIME::TIMEZONE +0300&amp;gt;
T&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we need to redefine the original &lt;code&gt;date-time&lt;/code&gt; rule, to create &lt;code&gt;local-time:timestamp&lt;/code&gt; as the result:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;date-time
                          &amp;quot;Thu, 13 Jul 2017 13:28:03 +0200&amp;quot;)
(&amp;quot;Thu&amp;quot; 13 7 2017 13 28 3 #&amp;lt;LOCAL-TIME::TIMEZONE +0200&amp;gt;)
T

POFTHEDAY&amp;gt; (parseq:defrule date-time ()
               (and (? (and day-of-week &amp;quot;,&amp;quot;))
                    date
                    time)
             (:choose &amp;#039;(1 2)                       ; year
                      &amp;#039;(1 1)                       ; month
                      &amp;#039;(1 0)                       ; day
                      &amp;#039;(2 0)                       ; hour
                      &amp;#039;(2 1)                       ; minute
                      &amp;#039;(2 2)                       ; second
                      &amp;#039;(2 3))                      ; timezone
             
             (:lambda (year month day hour minute second timezone)
               (local-time:encode-timestamp
                0             ; nanoseconds
                (or second 0) ; secs are optional
                minute
                hour
                day
                month
                year
                :timezone (or timezone
                              local-time:*default-timezone*))))

POFTHEDAY&amp;gt; (parseq:parseq &amp;#039;date-time
                          &amp;quot;Thu, 13 Jul 2017 13:28:03 +0200&amp;quot;)
@2017-07-13T14:28:03.000000+03:00
T&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I&apos;ve got a different value for the time because &lt;code&gt;local-time&lt;/code&gt; prints timestamp in my timezone which is &lt;code&gt;UTC+3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The cool feature of the Parseq is its ability to work with any data, including binary. This way it can be used to parse binary formats.&lt;/p&gt;
&lt;p&gt;As an example of parsing binary data, Parseq includes this parser rules for working with PNG image format:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/mrossini-ethz/parseq/blob/master/examples/png.lisp&quot;&gt;https://github.com/mrossini-ethz/parseq/blob/master/examples/png.lisp&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There are other interesting features. Please, read the docs to learn more.&lt;/p&gt;
&lt;p&gt;If you are aware of other parsing libraries which worth to be written about, let me know in the comments.&lt;/p&gt;
</description>
            <pubDate>Fri, 23 Oct 2020 23:47:49 +0300</pubDate>
        </item>
        <item>
            <title>pzmq</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/10/0206-pzmq.html</link>
            <description>&lt;p&gt;ZeroMQ is a networking library. It is not a message broker and it will not run tasks for you. Instead, it provides simple primitives for different network patterns.&lt;/p&gt;
&lt;p&gt;With ZeroMQ you can easily implement these patterns: Request-Response, Pub-Sub, Push-Pull.&lt;/p&gt;
&lt;p&gt;I found 3 CL systems implementing bindings to ZeroMQ:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;pzmq - &lt;a href=&quot;https://github.com/orivej/pzmq&quot;&gt;https://github.com/orivej/pzmq&lt;/a&gt; (ZeroMQ 4.0 bindings) active&lt;/li&gt;&lt;li&gt;zeromq &lt;a href=&quot;https://github.com/freiksenet/cl-zmq&quot;&gt;https://github.com/freiksenet/cl-zmq&lt;/a&gt; ZeroMQ 3 (7 years ago)&lt;/li&gt;&lt;li&gt;zmq &lt;a href=&quot;https://github.com/galdor/lisp-zmq&quot;&gt;https://github.com/galdor/lisp-zmq&lt;/a&gt; Up to ZeroMQ 3.2 (7 year ago)&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;I know, names of the repositories, CL systems and packages are all different. That is the HELL :(&lt;/p&gt;
&lt;p&gt;There is also at least two different versions of the &lt;code&gt;zmq&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;First one is referred by &lt;a href=&quot;https://www.cliki.net/cl-zmq&quot;&gt;https://www.cliki.net/cl-zmq&lt;/a&gt; and included   into Quicklisp. But examples from the ZeroMQ Guide not work with this   &lt;code&gt;zmq&lt;/code&gt; because &lt;code&gt;msg-data-as-is&lt;/code&gt; function is absent.&lt;/li&gt;&lt;li&gt;The second one is &lt;a href=&quot;https://github.com/tsbattman/cl-zmq&quot;&gt;https://github.com/tsbattman/cl-zmq&lt;/a&gt; and seems it is   the version, used in ZeroMQ Guide. But it is not in the Quicklisp (yet   or anymore).&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Anyway, both of them are stale and didn&apos;t get updates 7-8 years. They are using the old 3.2 version of ZeroMQ. Today we&apos;ll talk about &lt;code&gt;pzmq&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;PZMQ has some activity in the repository and uses ZeroMQ 4. It does not have docs but it has &lt;a href=&quot;https://github.com/orivej/pzmq/blob/master/examples.lisp&quot;&gt;some examples&lt;/a&gt;, ported from the &lt;a href=&quot;https://zguide.zeromq.org/docs/chapter1/&quot;&gt;ZeroMQ Guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I slightly modified the examples code, to make the output more readable when client and server are running from one REPL.&lt;/p&gt;
&lt;p&gt;This snippet shows the server&apos;s code. It listens on the 5555 port and blocks until a message received, then responds and waits for another message:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (defun hwserver (&amp;amp;optional (listen-address &amp;quot;tcp://*:5555&amp;quot;))
             (pzmq:with-context nil ; use *default-context*
               (pzmq:with-socket responder :rep
                 (pzmq:bind responder listen-address)
                 (loop
                   (write-line &amp;quot;SERVER: Waiting for a request... &amp;quot;)
                   (format t &amp;quot;SERVER: Received ~A~%&amp;quot;
                           (pzmq:recv-string responder))
                   (sleep 1)
                   (pzmq:send responder &amp;quot;World&amp;quot;)))))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The client does the opposite - it sends some data and waits for the response. Depending on the pattern you use, you have to set socket types. For the server, we used :rep (reply) and for client we are using :req (request).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (defun hwclient (&amp;amp;optional (server-address &amp;quot;tcp://localhost:5555&amp;quot;))
             (pzmq:with-context (ctx :max-sockets 10)
               (pzmq:with-socket (requester ctx) (:req :affinity 3 :linger 100)
                 ;; linger is important in case of (keyboard) interrupt;
                 ;; see http://api.zeromq.org/3-3:zmq-ctx-destroy
                 (write-line &amp;quot;CLIENT: Connecting to hello world server...&amp;quot;)
                 (pzmq:connect requester server-address)
                 (dotimes (i 3)
                   (format t &amp;quot;CLIENT: Sending Hello ~d...~%&amp;quot; i)
                   (pzmq:send requester &amp;quot;Hello&amp;quot;)
                   (write-string &amp;quot;CLIENT: Receiving... &amp;quot;)
                   (write-line (pzmq:recv-string requester))))))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here is what we&apos;ll see when running the server in the background and starting the client in the REPL:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (defparameter *server-thread*
             (bt:make-thread #&amp;#039;hwserver))

SERVER: Waiting for a request... 

POFTHEDAY&amp;gt; (hwclient)
CLIENT: Connecting to hello world server...
CLIENT: Sending Hello 0...
CLIENT: Receiving... Hello
SERVER: Waiting for a request... World
CLIENT: Sending Hello 1...
CLIENT: Receiving... Hello
SERVER: Waiting for a request... World
CLIENT: Sending Hello 2...
CLIENT: Receiving... Hello
SERVER: Waiting for a request... World
NIL&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What is next?&lt;/p&gt;
&lt;p&gt;Read about Pub-Sub and Push-Pull patterns at &lt;a href=&quot;https://zguide.zeromq.org/docs/chapter1/&quot;&gt;the ZeroMQ Guide&lt;/a&gt; and try to port them on &lt;code&gt;pzmq&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Also, it would be cool to port &lt;a href=&quot;https://github.com/booksbyus/zguide/tree/master/examples/CL&quot;&gt;all Common Lisp examples&lt;/a&gt; from the unsupported library to the &lt;code&gt;pzmq&lt;/code&gt; and to send a pull-request.&lt;/p&gt;
&lt;p&gt;By the way, there is at least one cool project, which already uses &lt;code&gt;pzmq&lt;/code&gt; to connect parts written in Common Lisp and Python. It is recently reviewed &lt;a href=&quot;https://40ants.com/lisp-project-of-the-day/2020/09/0197-common-lisp-jupyter.html&quot;&gt;common-lisp-jupyter&lt;/a&gt; library.&lt;/p&gt;
&lt;p&gt;To conclude, this library definitely should be tried if you are going to implement a distributed application! Especially if it will interop with parts written in other languages than Common Lisp.&lt;/p&gt;
</description>
            <pubDate>Mon, 19 Oct 2020 21:47:16 +0300</pubDate>
        </item>
        <item>
            <title>quickfork</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/10/0205-quickfork.html</link>
            <description>&lt;p&gt;This is an interesting system which provides information about other systems sources. Also, it is able to show commands, necessary to clone libraries into the local-projects dir.&lt;/p&gt;
&lt;p&gt;This system is not in Quicklisp yet, but it can be installed from Ultralisp or by clone into some directory like &lt;code&gt;&lt;/code&gt;/quicklisp/local-projects~.&lt;/p&gt;
&lt;p&gt;Also, to make it work, you have to clone &lt;code&gt;quicklisp-projects&lt;/code&gt; repository somewhere. This repository contains metadata about all projects in the Quicklisp:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (uiop:run-program
            &amp;quot;git clone https://github.com/quicklisp/quicklisp-projects /tmp/projects&amp;quot;)
POFTHEDAY&amp;gt; (setf quickfork::*projects-directory* &amp;quot;/tmp/projects/projects&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;An interesting thing happens right after you load &lt;code&gt;quickfork&lt;/code&gt; system. It installs a few hooks into Quicklisp and ASDF and begins tracking the systems which are installed during the &lt;code&gt;ql:quickload&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (ql:quickload :dexador)
To load &amp;quot;dexador&amp;quot;:
  Load 14 ASDF systems:
    alexandria asdf babel bordeaux-threads cffi cffi-grovel
    cl-ppcre cl-utilities flexi-streams local-time
    split-sequence trivial-features trivial-gray-streams
    uiop
  Install 17 Quicklisp releases:
    chipz chunga cl+ssl cl-base64 cl-cookie cl-reexport
    dexador fast-http fast-io proc-parse quri smart-buffer
    static-vectors trivial-garbage trivial-mimes usocket
    xsubseq
; Fetching #&amp;lt;URL &amp;quot;http://beta.quicklisp.org/archive/usocket/2019-12-27/usocket-0.8.3.tgz&amp;quot;&amp;gt;
; 83.84KB
...

; Loading &amp;quot;dexador&amp;quot;
...
[package cl+ssl]..................................
[package dexador].

Systems compiled by QL: 
 (&amp;quot;proc-parse&amp;quot;
  #P&amp;quot;/Users/art/poftheday/.qlot/dists/quicklisp/software/proc-parse-20190813-git/&amp;quot;)
 (&amp;quot;xsubseq&amp;quot;
  #P&amp;quot;/Users/art/poftheday/.qlot/dists/quicklisp/software/xsubseq-20170830-git/&amp;quot;)
  ...
 (&amp;quot;dexador&amp;quot;
  #P&amp;quot;/Users/art/poftheday/.qlot/dists/quicklisp/software/dexador-20200427-git/&amp;quot;)
Systems loaded by QL: 
 (&amp;quot;proc-parse&amp;quot;
  #P&amp;quot;/Users/art/poftheday/.qlot/dists/quicklisp/software/proc-parse-20190813-git/&amp;quot;)
 (&amp;quot;xsubseq&amp;quot;
  #P&amp;quot;/Users/art/poftheday/.qlot/dists/quicklisp/software/xsubseq-20170830-git/&amp;quot;)
 ...
 (&amp;quot;dexador&amp;quot;
  #P&amp;quot;/Users/art/poftheday/.qlot/dists/quicklisp/software/dexador-20200427-git/&amp;quot;)
Systems installed by QL: 
 &amp;quot;usocket&amp;quot;
 &amp;quot;trivial-mimes&amp;quot;
 ...
 &amp;quot;chipz&amp;quot;
 &amp;quot;dexador&amp;quot;
Inspect ql:*compiled-systems*, ql:*loaded-systems*, and ql:*installed-systems* for more info.
(:DEXADOR)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Also, there is a function &lt;code&gt;quickfork::make-clone-commands&lt;/code&gt; which prints which commands should be executed in command-line to clone given system and all its dependencies.&lt;/p&gt;
&lt;p&gt;Sadly, &lt;code&gt;quickfork::make-clone-commands&lt;/code&gt; fails on &lt;code&gt;dexador&lt;/code&gt; with some strange &lt;a href=&quot;https://github.com/svspire/quickfork/issues/1&quot;&gt;error&lt;/a&gt;s. You will need &lt;a href=&quot;https://github.com/svspire/quickfork/pull/2&quot;&gt;my fix&lt;/a&gt;, to make it work like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;CL-USER&amp;gt; (quickfork::make-clone-commands :dexador)

git clone  &amp;quot;https://github.com/sharplispers/split-sequence.git&amp;quot;
git clone  &amp;quot;https://github.com/sionescu/static-vectors.git&amp;quot;
git clone  &amp;quot;https://github.com/sionescu/bordeaux-threads.git&amp;quot;
git clone  &amp;quot;https://github.com/fukamachi/dexador.git&amp;quot;
git clone  &amp;quot;https://github.com/fukamachi/fast-http.git&amp;quot;
git clone  &amp;quot;https://gitlab.common-lisp.net/alexandria/alexandria.git&amp;quot;
git clone  &amp;quot;https://github.com/fukamachi/proc-parse.git&amp;quot;
git clone  &amp;quot;https://github.com/cl-babel/babel.git&amp;quot;
git clone  &amp;quot;https://github.com/trivial-features/trivial-features.git&amp;quot;
git clone  &amp;quot;https://github.com/fukamachi/xsubseq.git&amp;quot;
git clone  &amp;quot;https://github.com/fukamachi/smart-buffer.git&amp;quot;
git clone  &amp;quot;https://github.com/trivial-gray-streams/trivial-gray-streams.git&amp;quot;
git clone  &amp;quot;https://github.com/fukamachi/quri.git&amp;quot;
git clone  &amp;quot;https://github.com/rpav/fast-io.git&amp;quot;
git clone  &amp;quot;https://github.com/fukamachi/cl-cookie.git&amp;quot;
git clone  &amp;quot;https://github.com/dlowe-net/local-time.git&amp;quot;
git clone  &amp;quot;https://github.com/Shinmera/trivial-mimes.git&amp;quot;
git clone  &amp;quot;https://github.com/sharplispers/chipz.git&amp;quot;
git clone  &amp;quot;https://github.com/takagi/cl-reexport.git&amp;quot;
git clone  &amp;quot;https://github.com/cl-plus-ssl/cl-plus-ssl.git&amp;quot;
git clone  &amp;quot;https://github.com/lmj/global-vars.git&amp;quot;
git clone  &amp;quot;https://github.com/trivial-garbage/trivial-garbage.git&amp;quot;

Non-git dependencies:
(&amp;quot;cl-utilities&amp;quot; :HTTPS
 &amp;quot;https://common-lisp.net/project/cl-utilities/cl-utilities-latest.tar.gz&amp;quot;)
NIL
(&amp;quot;flexi-streams&amp;quot; :EDIWARE-HTTP &amp;quot;flexi-streams&amp;quot;)
(&amp;quot;uiop&amp;quot; :HTTPS &amp;quot;https://common-lisp.net/project/asdf/archives/uiop.tar.gz&amp;quot;)
(&amp;quot;cffi&amp;quot; :HTTPS
 &amp;quot;https://common-lisp.net/project/cffi/releases/cffi_latest.tar.gz&amp;quot;)
(&amp;quot;chunga&amp;quot; :EDIWARE-HTTP &amp;quot;chunga&amp;quot;)
(&amp;quot;cl-ppcre&amp;quot; :EDIWARE-HTTP &amp;quot;cl-ppcre&amp;quot;)
(&amp;quot;cl-base64&amp;quot; :KMR-GIT &amp;quot;cl-base64&amp;quot;)
(&amp;quot;usocket&amp;quot; :HTTPS
 &amp;quot;https://common-lisp.net/project/usocket/releases/usocket-latest.tar.gz&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Suddenly, I&apos;ve remembered another similar project: &lt;code&gt;ql-checkout&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Probably, yesterday we&apos;ll see how it works!&lt;/p&gt;
</description>
            <pubDate>Fri, 16 Oct 2020 22:32:51 +0300</pubDate>
        </item>
        <item>
            <title>font-discovery</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/10/0204-font-discovery.html</link>
            <description>&lt;p&gt;This is a library by &lt;a href=&quot;https://twitter.com/Shinmera&quot;&gt;@Shinmera&lt;/a&gt; to find out which fonts are known to OS and where their files are located.&lt;/p&gt;
&lt;p&gt;Here is how you can list all &quot;Arial&quot; fonts and find where the &quot;bold&quot; version is located:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (org.shirakumo.font-discovery:list-fonts :family &amp;quot;Arial&amp;quot;)
(#&amp;lt;ORG.SHIRAKUMO.FONT-DISCOVERY:FONT &amp;quot;Arial&amp;quot; ROMAN REGULAR NORMAL&amp;gt;
 #&amp;lt;ORG.SHIRAKUMO.FONT-DISCOVERY:FONT &amp;quot;Arial&amp;quot; ITALIC REGULAR NORMAL&amp;gt;
 #&amp;lt;ORG.SHIRAKUMO.FONT-DISCOVERY:FONT &amp;quot;Arial&amp;quot; ROMAN BOLD NORMAL&amp;gt;
 #&amp;lt;ORG.SHIRAKUMO.FONT-DISCOVERY:FONT &amp;quot;Arial&amp;quot; ITALIC BOLD NORMAL&amp;gt;)

POFTHEDAY&amp;gt; (third *)
#&amp;lt;ORG.SHIRAKUMO.FONT-DISCOVERY:FONT &amp;quot;Arial&amp;quot; ROMAN BOLD NORMAL&amp;gt;

POFTHEDAY&amp;gt; (org.shirakumo.font-discovery:file *)
#P&amp;quot;/System/Library/Fonts/Supplemental/Arial Bold.ttf&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It is also possible to find a single font filtering it by family, slant and other parameters:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (org.shirakumo.font-discovery:find-font :family &amp;quot;PragmataPro&amp;quot;)
#&amp;lt;ORG.SHIRAKUMO.FONT-DISCOVERY:FONT &amp;quot;PragmataPro&amp;quot; ROMAN REGULAR NORMAL&amp;gt;

POFTHEDAY&amp;gt; (describe *)
#&amp;lt;ORG.SHIRAKUMO.FONT-DISCOVERY:FONT &amp;quot;PragmataPro&amp;quot; ROMAN REGULAR NORMAL&amp;gt;
  [standard-object]

Slots with :INSTANCE allocation:
  FILE                           = #P&amp;quot;/Users/art/Library/Fonts/PragmataProR_0828.ttf&amp;quot;
  FAMILY                         = &amp;quot;PragmataPro&amp;quot;
  SLANT                          = :ROMAN
  WEIGHT                         = :REGULAR
  SPACING                        = NIL
  STRETCH                        = :NORMAL&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;However, I found this library is still unstable on OSX and sometimes crashes somewhere in the CFFI code. @Shinmera has fixed some of these errors but some of them are still uncaught.&lt;/p&gt;
&lt;p&gt;Read the full documentation on it here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://shinmera.github.io/font-discovery/&quot;&gt;https://shinmera.github.io/font-discovery/&lt;/a&gt;&lt;/p&gt;
</description>
            <pubDate>Wed, 14 Oct 2020 23:52:55 +0300</pubDate>
        </item>
        <item>
            <title>tesseract-capi</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/10/0203-tesseract-capi.html</link>
            <description>&lt;p&gt;It has nothing in common with the magic artefact, but anyway is able to do pretty cool things!&lt;/p&gt;
&lt;p&gt;This library is a wrapper around &lt;a href=&quot;https://tesseract-ocr.github.io/&quot;&gt;Tesseract OCR&lt;/a&gt; and is suitable for an image to text transformations.&lt;/p&gt;
&lt;p&gt;To test this system, you need to install the &lt;code&gt;Tesseract&lt;/code&gt; library first. On OSX just do:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;bash&apos;&gt;brew install tesseract&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The CL library is not in the Quicklisp but can be installed from the &lt;a href=&quot;https://ultralisp.org&quot;&gt;https://ultralisp.org&lt;/a&gt; Follow the instruction from the repository:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/egao1980/tesseract-capi&quot;&gt;https://github.com/egao1980/tesseract-capi&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To make it work, you&apos;ll need a trained data for Tesseract engine. Happily, the Homebrew package includes some files for the English language.&lt;/p&gt;
&lt;p&gt;To find out a path, do:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;bash&apos;&gt;[poftheday] echo $(brew --prefix tesseract)/share/tessdata/
/usr/local/opt/tesseract/share/tessdata/&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we can test this library on this sample from the repository:&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;max-width: 100%&quot; src=&quot;../../media/0203/fox.png&quot;/&gt;&lt;/p&gt;
&lt;p&gt;Here is how to translate this image into the text:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (tesseract-capi::tessversion)
&amp;quot;4.1.1&amp;quot;

POFTHEDAY&amp;gt; (let ((tesseract-capi:*tessdata-directory*
                   &amp;quot;/usr/local/opt/tesseract/share/tessdata/&amp;quot;))
             (tesseract-capi:image-to-text
              (asdf:system-relative-pathname
               :tesseract-capi &amp;quot;tests/data/fox.png&amp;quot;)))
&amp;quot;This is a lot of 12 point text to test the
ocr code and see if it works on all types
of fle format

The quick brown dog jumped over the
lazy fox. The quick brown dog jumped
over the lazy fox. The quick brown dog
jumped over the lazy fox. The quick
brown dog jumped over the lazy fox
&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now let&apos;s try it on this &lt;a href=&quot;https://xkcd.com/312/&quot;&gt;XKCD&lt;/a&gt; comic:&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;max-width: 100%&quot; src=&quot;../../media/0203/xkcd-312.png&quot;/&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (let ((tesseract-capi:*tessdata-directory*
                   &amp;quot;/usr/local/opt/tesseract/share/tessdata/&amp;quot;))
             (tesseract-capi:image-to-text
              &amp;quot;docs/media/0203/xkcd-312.png&amp;quot;))
&amp;quot;A GODS LAMENT
SOME SAID THE WORLD SHOULD BE IN PERL;
SOME. SAID IN LISP
NOW, HAVING GIVEN BOTH A WHIRL,
I HELD WITH THOSE WHO FAVORED PERL.
BUT I FEAR WE PASSED TO MEN
A DISAPPOINTING FOUNDING MYTH,
AND SHOULD WE WRITE IT ALL AGAIN,
TO ENO IT WITH
A CLOSE -PAREN.
SY i
\\ ad an ran
cS co V
a, em oo
2 ee eee
@ P= : } 0.\&amp;quot; :
a OO
&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see, it outputs some junk at the end, but main text is recognized almost perfectly!&lt;/p&gt;
&lt;p&gt;I think, this is a pretty cool library! For example, you can use it plus &lt;a href=&quot;https://github.com/sharplispers/montezuma&quot;&gt;Montezuma&lt;/a&gt; to build a personal search engine for your image and scans collection. It&apos;s a matter of one night.&lt;/p&gt;
</description>
            <pubDate>Mon, 12 Oct 2020 23:24:53 +0300</pubDate>
        </item>
        <item>
            <title>cl-cont</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/10/0202-cl-cont.html</link>
            <description>&lt;p&gt;This is a pretty old system which implements Delimited Continuations for Common Lisp. Initially, it was part of the Weblocks web-framework.&lt;/p&gt;
&lt;p&gt;Sadly, but cl-cont has no documentation. I found only one example on &lt;a href=&quot;https://common-lisp.net/project/cl-cont/&quot;&gt;this page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It always was hard to wrap my mind around continuations. Probably that is why I decided to remove their support from the core of the Weblocks when I did the refactoring.&lt;/p&gt;
&lt;p&gt;Now it is time to dive into continuations and probably to return them to Weblocks as an additional library.&lt;/p&gt;
&lt;p&gt;Let&apos;s see what continuation is and how they can be used in practice!&lt;/p&gt;
&lt;p&gt;The first thing to note is that each piece of code which uses this magic should be wrapped into &lt;code&gt;with-call/cc&lt;/code&gt;. The second thing to remember is that &lt;code&gt;let/cc&lt;/code&gt; form allows you to capture the moment and to save the execution point somewhere.&lt;/p&gt;
&lt;p&gt;The code below prints three lines. It prints &quot;Begin&quot;, then captures the execution point, prints &quot;Before returning&quot; and returns the captured point:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (cont:with-call/cc
             (format t &amp;quot;Begin~%&amp;quot;)
             (cont:let/cc k
               (format t &amp;quot;Before returning k~%&amp;quot;)
               k)
             (format t &amp;quot;End~%&amp;quot;)
             :final-result)
Begin
Before returning k
#&amp;lt;FUNCTION (LAMBDA (&amp;amp;OPTIONAL #:G1455 &amp;amp;REST #:G1456)) {22A10A0B}&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What has happened to our third print &quot;End&quot;? It didn&apos;t have a chance to be executed yet. But we can continue execution, by calling the function we&apos;ve received as the result on the previous code snippet:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (funcall *)
End
:FINAL-RESULT

POFTHEDAY&amp;gt; (funcall **)
End
:FINAL-RESULT&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That is why it is called &quot;continuation&quot;! Yeah! As you can see, we can call this captured function any amount of times.&lt;/p&gt;
&lt;p&gt;Now, let&apos;s try to create a function which will interrupt its execution and return a continuation.&lt;/p&gt;
&lt;p&gt;Our first attempt might be like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (defun foo ()
             (cont:with-call/cc
               (format t &amp;quot;Begin foo~%&amp;quot;)
               (cont:let/cc k
                 (format t &amp;quot;Before returning k from foo~%&amp;quot;)
                 k)
               (format t &amp;quot;End foo~%&amp;quot;)
               :final-result))

POFTHEDAY&amp;gt; (cont:with-call/cc
             (format t &amp;quot;Before foo~%&amp;quot;)
             (foo)
             (format t &amp;quot;After foo~%&amp;quot;))
Before foo
Begin foo
Before returning k from foo
After foo ;; Ups! I&amp;#039;ve expected it will not output this
NIL       ;; and return a continuation function instead of NIL!&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As you can see, only half of our function was executed and then control flow continued, printed &quot;After foo&quot; and finished without giving us any continuation to play with :(&lt;/p&gt;
&lt;p&gt;To make this code work as expected, we need to move &lt;code&gt;with-call/cc&lt;/code&gt; form and make it wrap the function definition:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (cont:with-call/cc
             (defun foo-wrapped ()
               (format t &amp;quot;Begin foo~%&amp;quot;)
               (cont:let/cc k
                 (format t &amp;quot;Before returning k from foo~%&amp;quot;)
                 k)
               (format t &amp;quot;End foo~%&amp;quot;)
               :final-result))


POFTHEDAY&amp;gt; (cont:with-call/cc
             (format t &amp;quot;Before foo~%&amp;quot;)
             (foo-wrapped)
             (format t &amp;quot;After foo~%&amp;quot;))
Before foo
Begin foo
Before returning k from foo
#&amp;lt;CLOSURE (LAMBDA (&amp;amp;OPTIONAL #:G1561 &amp;amp;REST #:G1562)) {10067F637B}&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This version works exactly as I&apos;ve expected. It halts execution inside the &lt;code&gt;foo&lt;/code&gt;&apos;s call and returns this continuation.&lt;/p&gt;
&lt;p&gt;Now we can call continuation to continue computation of the foo function and the rest of our top-level form:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (funcall *)
End foo
After foo
NIL&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The latter case works because &lt;code&gt;cont:with-call/cc&lt;/code&gt; is smart enough and if it wraps the function &lt;code&gt;foo-wrapped&lt;/code&gt; into a special funcallable object:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;;; This function is usual:
POFTHEDAY&amp;gt; (fdefinition &amp;#039;foo)
#&amp;lt;FUNCTION FOO&amp;gt;

;; But this one is not.
;; It supports nested continuations:
POFTHEDAY&amp;gt; (fdefinition &amp;#039;foo-wrapped)
#&amp;lt;CL-CONT::FUNCALLABLE/CC {10063435FB}&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now let&apos;s adapt some examples from this Wikipedia &lt;a href=&quot;https://en.wikipedia.org/wiki/Continuation&quot;&gt;article about continuations&lt;/a&gt;. The first example shows how to save continuation into the global variable and what happens when you use the same function to create the second continuation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (defvar *the-continuation*)

POFTHEDAY&amp;gt; (cont:defun/cc test ()
             (let ((i 0))
               ;; let/cc binds to k symbol a variable representing
               ;; this point in the program as the argument to
               ;; that function.
               ;;
               ;; In this case, we assigns that
               ;; continuation to the variable *the-continuation*
               ;; and then return the incremented value of &amp;#039;i&amp;#039;.
               ;;
               (cont:let/cc k
                 (setf *the-continuation* k)
                 (incf i))

               ;; The next time *the-continuation* is called,
               ;; we start here:
               (incf i)))

POFTHEDAY&amp;gt; (test)
1

POFTHEDAY&amp;gt; (funcall *the-continuation*)
2

POFTHEDAY&amp;gt; (funcall *the-continuation*)
3

;; Stores the current continuation (which will print 4 next) away
POFTHEDAY&amp;gt; (defparameter *another-continuation* *the-continuation*)

;; Resets *the-continuation*:
POFTHEDAY&amp;gt; (test)
1

POFTHEDAY&amp;gt; (funcall *the-continuation*)
2

;; Uses the previously stored continuation:
POFTHEDAY&amp;gt; (funcall *another-continuation*)
4&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The second example is more interesting because it let us create a simple framework for running &lt;a href=&quot;https://en.wikipedia.org/wiki/Green_threads&quot;&gt;green threads&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, we need to define such two primitives: &lt;code&gt;fork&lt;/code&gt; and &lt;code&gt;yield&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (defparameter *queue* nil)

POFTHEDAY&amp;gt; (defun empty-queue? ()
             (null *queue*))

POFTHEDAY&amp;gt; (defun enqueue (func)
             (setf *queue*
                   (append *queue*
                           (list func))))

POFTHEDAY&amp;gt; (defun dequeue ()
             (pop *queue*))

;; This stops running the current thread by placing it into the queue
;; and starts running a (func).
POFTHEDAY&amp;gt; (cont:defun/cc fork (func &amp;amp;rest args)
             (cont:let/cc k
               (enqueue k)
               (apply func args)))

;; This stops running the current thread by placing it into the queue
;; and starts running the other thread from the queue if there is any:
POFTHEDAY&amp;gt; (cont:defun/cc yield ()
             (cont:let/cc k
               (enqueue k)
               (funcall (dequeue))))&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;How does &lt;code&gt;fork&lt;/code&gt; function work?&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;;; This is the function we want to run in &amp;quot;parallel&amp;quot;:
POFTHEDAY&amp;gt; (defun do-job ()
             (format t &amp;quot;Inside job~%&amp;quot;))

;; Initially, our queue is empty:
POFTHEDAY&amp;gt; *queue*
NIL

;; Now when we&amp;#039;ll call the fork,
;; it will:
;;
;; - capture current continuation;
;; - put it into the queue;
;; - execute do-job function.
POFTHEDAY&amp;gt; (cont:with-call/cc
             (format t &amp;quot;Before fork~%&amp;quot;)
             (fork #&amp;#039;do-job)
             (format t &amp;quot;After fork~%&amp;quot;))
Before fork
Inside job
NIL

;; Now queue has one function which is
;; the rest of our initial computation.
POFTHEDAY&amp;gt; *queue*
(#&amp;lt;FUNCTION (LAMBDA (&amp;amp;OPTIONAL #:G1655 &amp;amp;REST #:G1656)) {22A1719B}&amp;gt;)

;; When the rest of the computation gets called,
;; it prints &amp;quot;After fork&amp;quot; and exits:
POFTHEDAY&amp;gt; (funcall (dequeue))
After fork
NIL&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Yield works similarly. It captures the current continuation, appends it to the queue, takes the next coroutine from the top of the queue and executes it.&lt;/p&gt;
&lt;p&gt;To test how two coroutines will behave when running in parallel, let&apos;s create a function which will print its name in the loop. On each iteration a coroutine will call &lt;code&gt;yield&lt;/code&gt; to give other coroutines a chance to get executed:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (cont:defun/cc do-stuff-n-print (name)
             (loop for n from 1 upto 3
                   do (format t &amp;quot;~A ~A~%&amp;quot; name n)
                      (yield)
                      (sleep 1)))

;; We also need to add this primive to our framework
POFTHEDAY&amp;gt; (defun wait-for-threads ()
             (loop
               when (empty-queue?)
                 return nil
               do (funcall (dequeue))))

POFTHEDAY&amp;gt; (cont:with-call/cc
             (fork #&amp;#039;do-stuff-n-print &amp;quot;Foo&amp;quot;)
             (fork #&amp;#039;do-stuff-n-print &amp;quot;Bar&amp;quot;)
             (wait-for-threads))
Foo 1
Bar 2
Foo 3
Bar 1
Foo 2
Bar 3&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The result we&apos;ve got is the same as the result of the Wikipedia article. Messages from both coroutines are interleaving. That is great!&lt;/p&gt;
&lt;p&gt;Now, cl-cont does not look so strange to me. It is time to reimplement continuation widgets for the Weblocks! :)&lt;/p&gt;
</description>
            <pubDate>Sat, 10 Oct 2020 23:52:05 +0300</pubDate>
        </item>
        <item>
            <title>lmdb</title>
            <link>http://40ants.com/lisp-project-of-the-day/2020/10/0201-lmdb.html</link>
            <description>&lt;p&gt;This is a binding to the embedded database &lt;a href=&quot;http://www.lmdb.tech/doc/index.html&quot;&gt;LMDB&lt;/a&gt;, mentioned in &lt;a href=&quot;https://twitter.com/kssreeram/status/1314080608008564737&quot;&gt;this tweet&lt;/a&gt;. LMDB is a fast key/value database which can be embedded into your app as a C library.&lt;/p&gt;
&lt;p&gt;Documentation on LMDB says it is really fast. I found this &lt;a href=&quot;https://dgraph.io/blog/post/badger-lmdb-boltdb/&quot;&gt;performance benchmark&lt;/a&gt; which compares it to the BoltDB and Badger. According to it, LMDB is slightly faster than BoldDB, but both lose to Badger.&lt;/p&gt;
&lt;p&gt;It would be interesting to make our own benchmarks, but to compare LMDB with &lt;a href=&quot;https://github.com/death/leveldb&quot;&gt;LevelDB&lt;/a&gt; which also has a binding to Common Lisp. But that is a story for another day.&lt;/p&gt;
&lt;p&gt;Here is a fixed and slightly modified example from the CL wrapper&apos;s README. It just writes a string by the key and reads it back:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&apos;lisp&apos;&gt;POFTHEDAY&amp;gt; (let ((env (lmdb:make-environment #p&amp;quot;./the-database/&amp;quot;)))
             (lmdb:with-environment (env)
               ;; Create a transaction
               (let ((txn (lmdb:make-transaction env)))
                 (lmdb:begin-transaction txn)
                 ;; Create a database access object
                 (let ((db (lmdb:make-database txn &amp;quot;db&amp;quot;)))
                   (lmdb:with-database (db)
                     ;; Here is how we can write some data to the storage
                     (lmdb:put db &amp;quot;the key&amp;quot; &amp;quot;The string&amp;quot;)
                     ;; and read it back:
                     (let ((vec (lmdb:get db &amp;quot;the key&amp;quot;)))
                       (print vec)))))))

;; Pay attention, the data is returned as a vector and your
;; app have to interpret it:
#(84 104 101 32 115 116 114 105 110 103)

POFTHEDAY&amp;gt; (babel:octets-to-string *)
&amp;quot;The string&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;What is interesting, I found this library was used in this Wiki software, written in Common Lisp: &lt;a href=&quot;https://github.com/antimer/antimer&quot;&gt;Antimer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But LMDB backend was removed from Antimer at &lt;a href=&quot;https://github.com/antimer/antimer/commit/b36a87044a61863cd7af535a91831c5bf4c11648&quot;&gt;some moment&lt;/a&gt; and replaced with SQLite. Most probably because it needed the full power of SQL instead of simple key-value queries.&lt;/p&gt;
&lt;p&gt;To finalize, this LMDB binding would be a good solution for small apps which makes simple queries and need a high-performance and low latency.&lt;/p&gt;
&lt;p&gt;BTW, the LMDB&apos;s &lt;a href=&quot;https://github.com/antimer/lmdb&quot;&gt;repository&lt;/a&gt; needs some love because there are some hanging pull requests and a few unanswered issues. Does somebody know how does Fernando Borretti feels himself? Maybe he needs some help?&lt;/p&gt;
</description>
            <pubDate>Thu, 08 Oct 2020 23:55:01 +0300</pubDate>
        </item>
    </channel>
</rss>