<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>stex.codes</title>
    <description>Stefan Exner | Freelancing Digital Solution Architect from Hamburg, Germany</description>
    <link>https://stex.codes/</link>
    <atom:link href="nathanrooy.github.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Thu, 31 Oct 2024 20:53:13 +0100</pubDate>
    <lastBuildDate>Thu, 31 Oct 2024 20:53:13 +0100</lastBuildDate>
    <generator>Jekyll v4.3.0</generator>
      
    
    <item>
        <title>Cypress on Rails 2: Electric Boogaloo</title>
        <description>&lt;p&gt;Today I held an updated version of my &lt;a href=&quot;/2020/12/09/cypress-on-rails-talk.html&quot;&gt;Cypress on Rails&lt;/a&gt; talk
at the &lt;a href=&quot;https://hamburg.onruby.de/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hamburg Ruby UserGroup&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The talk covers an introduction to Cypress, how to communicate with a Rails server from Cypress
to e.g. generate test data with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;factory_bot&lt;/code&gt; and a way to run Cypress tests in CI
with spinning up the Rails application as a service in Gitlab CI or Github Actions.&lt;/p&gt;

&lt;p&gt;We had a great discussion about responsibility for e2e tests (is it the backend team? is it the frontend team? why not both?)
and whether e2e tests are needed at all when backend/frontend specific tests exist.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/stex/cypress_demo/blob/main/pitch/cypress-on-rails.pdf&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;The slides&lt;/a&gt; can be found over at Github together with a &lt;a href=&quot;https://github.com/stex/cypress_demo&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;demo project&lt;/a&gt; that contains&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;a Rails 7 application with Rodauth and Turbo Frames and ActionText usage&lt;/li&gt;
  &lt;li&gt;a small Cypress test suite&lt;/li&gt;
  &lt;li&gt;Dockerfiles for both the application and Cypress&lt;/li&gt;
  &lt;li&gt;a Github Actions configuration to build the Docker images and run the Cypress tests with the Rails Application as Service container&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks to everyone who attended the meetup, it was great talking to you!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://images.stex.codes/o2wMxHR_BQ8S7UGpPcqrAchNcyI=/950x0/smart/https://stex.codes/assets/images/posts/2022-11-09-thank-you.jpg&quot; alt=&quot;Thank You!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;All image were generated by &lt;a href=&quot;https://labs.openai.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;DALL-E&lt;/a&gt;, there are a few more in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pitch&lt;/code&gt; folder that were not used if you’re interested 🙂&lt;/small&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 09 Nov 2022 00:00:00 +0100</pubDate>
        
        <link>/2022/11/09/cypress-on-rails-2-electric-boogaloo.html</link>
          
        
            <category>cypress</category>
        
            <category>rails</category>
        
            <category>end-to-end-tests</category>
        
            <category>capybara</category>
        
            <category>talk</category>
        
          
        
            <category>programming</category>
        
          
      </item>
    
    <item>
        <title>Importing an external Feed into Jekyll</title>
        <description>&lt;p&gt;A simple script approach to import posts from an external feed into a Jekyll blog using HEY World’s atom feed as an example. Contains some special workarounds to fix the feed’s contents, but should work with every well-formed RSS feed out there with a little customisation.&lt;/p&gt;

&lt;p&gt;As seen in &lt;a href=&quot;https://stex.codes/2021/05/14/hey-testing-hey-world.html&quot;&gt;my test post&lt;/a&gt;, I tried HEY World, a new blogging service by Basecamp that works by sending an email that’s then published to the web. While it’s not the most powerful blogging tool, it’s definitely one that’s easy to use.&lt;/p&gt;

&lt;p&gt;To keep everything in one place and enjoy basic functionality like syntax highlighting even for the posts made in HEY World, I decided to import the feed they provide into my homepage and fix a few things on the way.&lt;br /&gt;
I am aware that this might lead to some SEO issues in case Google considers this to be double content, but I’ll cross that bridge when I get there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; Of course I noticed a few problems just after writing this post, e.g. that tags were no longer extracted in all cases. I made my script more fail-safe and updated the parts below. Here’s the &lt;a href=&quot;https://world.hey.com/stex/importing-an-external-feed-into-jekyll-3b112301&quot;&gt;post on HEY World&lt;/a&gt; to see the script in action.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/Stex/stex.codes/blob/master/bin/sync_hey_world_posts&quot;&gt;Here’s the latest version of the script&lt;/a&gt;, I’ll go into some of the problems I ran into that are HEY World specific though. Parsing the feed was done using &lt;a href=&quot;https://github.com/feedjira/feedjira&quot;&gt;feedjira&lt;/a&gt; which is an amazingly easy to use library for all kinds of XML feeds, so I’ll skip this part.&lt;/p&gt;

&lt;h2 id=&quot;converting-the-post-content&quot;&gt;Converting the Post Content&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/basecamp/trix&quot;&gt;Trix&lt;/a&gt;, the WYSIWYG editor used by &lt;a href=&quot;https://edgeguides.rubyonrails.org/action_text_overview.html&quot;&gt;Rails’ Action Text&lt;/a&gt; and consequently by HEY, produces HTML which is used as entry content in the atom feed. It looks like they just insert the &lt;a href=&quot;https://edgeguides.rubyonrails.org/action_text_overview.html#rendering-rich-text-content&quot;&gt;default trix layout&lt;/a&gt; which still contains e.g. a surrounding &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;div.trix-content&lt;/code&gt; and a lot of formatting with a few… interesting choices.&lt;/p&gt;

&lt;p&gt;To make this as easy for me as possible, I decided to convert the HTML I get from HEY into markdown and get rid of all HTML that’s not inside &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pre&lt;/code&gt; tags. There’s a great gem called &lt;a href=&quot;https://github.com/xijo/reverse_markdown&quot;&gt;reverse_markdown&lt;/a&gt; out there that I already used in the past and in a perfect world, all I’d have to do was a one-liner on the content:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;ReverseMarkdown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;github_flavored: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;unknown_tags: :bypass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However, I had to work around a few of Trix’s behaviours as well as get some additional information out of the post beforehand:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Trix and its Lack of Paragraphs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Other editors usually produce a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag for a double newline, Trix goes the literal way and inserts two &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;br&amp;gt;&lt;/code&gt; tags. Not wrong, but a bit unexpected and a bit difficult when it comes to markdown conversion.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reverse_markdown&lt;/code&gt; conversion rule for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;br&amp;gt;&lt;/code&gt; tags:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Br&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{})&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, it inserts 2 spaces and a newline which is “stay in the same paragraph, but start a new line” in markdown. So, what happens with Trix’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/code&gt; pattern?&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s2&quot;&gt;&quot;hello&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;world&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_markdown&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;hello &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;world&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While &lt;a href=&quot;https://kramdown.gettalong.org/&quot;&gt;kramdown&lt;/a&gt;, the default markdown parser in Jekyll, ultimately converts this into paragraphs as it ignores the spaces at the end of the lines, Jekyll seems to have problems generating a post teaser out of this. By default, Jekyll takes the first paragraphs of a post for the index page tiles (depending on their length), but was unable to do so with the double &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;br&amp;gt;&lt;/code&gt; tags:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://world.hey.com/stex/3b112301/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCQUQ4RUJnPSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--f3624e296d5ca0736bcc794204369150b2c88881/image.png?disposition=attachment&quot; title=&quot;Download image.png&quot;&gt;&lt;img src=&quot;https://world.hey.com/stex/3b112301/representations/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCQUQ4RUJnPSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--f3624e296d5ca0736bcc794204369150b2c88881/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDam9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2RkhKbGMybDZaVjkwYjE5c2FXMXBkRnNIYVFLQUIya0NBQVU2REhGMVlXeHBkSGxwU3pvTGJHOWhaR1Z5ZXdZNkNYQmhaMlV3T2cxamIyRnNaWE5qWlZRPSIsImV4cCI6bnVsbCwicHVyIjoidmFyaWF0aW9uIn19--946116ea0c454412635aa7309bd9472bf633014c/image.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It looks like everything up to the code block was interpreted as a single paragraph (which is correct as explained above). To work around this with as little work as possible, I decided to introduce an own pseudo HTML tag as replacement for the double &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;br&amp;gt;&lt;/code&gt;s that I could translate to markdown myself:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DoubleBr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;s2&quot;&gt;&quot;hello&amp;lt;doublebr /&amp;gt;world&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_markdown&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#=&amp;gt; &quot;hello\n\nworld&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2. Headings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While the HEY editor provides a “Heading” style, it seems to only be able to produce &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;H1&lt;/code&gt; tags which is probably not the semantically best way to go on a website. &lt;/p&gt;

&lt;p&gt;I therefore decided to add an own markdown converter again which simply translates &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;H1&lt;/code&gt; into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;##&lt;/code&gt;. Works well and since I know that the input will never contain any other headings, this shouldn’t cause problems in the future.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Producing proper Code Blocks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While Trix has a basic code block functionality, it doesn’t support syntax highlighting, but introduces a few formatting tags like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;em&amp;gt;&lt;/code&gt; into the code.&lt;/p&gt;

&lt;p&gt;What it doesn’t do is inserting a proper &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;code&amp;gt;&lt;/code&gt; tag inside its &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;pre&amp;gt;&lt;/code&gt;s which would be &lt;a href=&quot;https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element&quot;&gt;the semantically correct way&lt;/a&gt; to display a block of code. I understand that they intended to simply provide a “we won’t touch whitespace here” functionality into their editor, but this behaviour made it harder to further process it.&lt;/p&gt;

&lt;p&gt;First, I had to get rid of the extra formatting HTML that’s inserted into the code block. Luckily, the actual code contains twice encoded HTML entities while the formatting tags were only encoded once for the feed:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# A comment&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;lt;&lt;/span&gt;em&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&lt;/span&gt;
  A comment
&lt;span class=&quot;ni&quot;&gt;&amp;amp;lt;&lt;/span&gt;/em&lt;span class=&quot;ni&quot;&gt;&amp;amp;gt;&lt;/span&gt;

class &lt;span class=&quot;ni&quot;&gt;&amp;amp;amp;&lt;/span&gt;lt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;amp;&lt;/span&gt;lt; self
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This way, it’s possible to decode it once and let Nokogiri remove all actual HTML tags while keeping the content intact. The easiest way to achieve this was to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#content&lt;/code&gt; on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; itself which returns the pure text content of said node.&lt;/p&gt;

&lt;p&gt;Additionally, I needed to alter two things in the HTML I got from HEY World: &lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Add a code tag so the markdown converter understands that this is in fact code&lt;/li&gt;
  &lt;li&gt;Extract the language to be highlighted&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To achieve 2), I added e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;# lang: ruby&lt;/code&gt; to the bottom of code blocks in the HEY World editor and extract these lines in my script.&lt;/p&gt;

&lt;p&gt;The resulting part of the script was pretty easy in the end:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;pre&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Nokogiri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;XML&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;code&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Search for a &quot;lang: something&quot; line at the end of the pre.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# If there is one, use it for syntax highlighting&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/lang: (\w+)/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lang&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pre&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I had to extend &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reverse_markdown&lt;/code&gt; again with an own converter for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;code&amp;gt;&lt;/code&gt; though as by default it doesn’t take the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lang&lt;/code&gt; attribute into account:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;TrixPre&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Pre&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;language&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;presence&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;at_css&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;code&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lang&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;4. Assigning Tags to Posts&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since HEY World itself doesn’t support tags, I used the same approach as for the code block highlighting language and search for a tag line (“#tag1 #tag2”) at the end of the post. I originally did this before turning the post into markdown, but the HTML I got wasn’t consistent enough, so I now treat the last markdown line as possible tags.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tags&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;begin&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;tag_line&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;markdown_content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lines&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tag_line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;match?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/^((#\w+) ?)+$/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;tag_line&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/#(\w+)/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If a tag line exists in the markdown content, it is removed before writing it to disk.&lt;/p&gt;

&lt;h2 id=&quot;front-matter&quot;&gt;Front Matter&lt;/h2&gt;

&lt;p&gt;The front matter for the Jekyll post (the YAML part at the beginning that contains the post’s title and other information) can be easily generated now that all relevant information has been extracted from the RSS entry:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;entry&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;id&amp;gt;&lt;/span&gt;tag:world.hey.com,2005:World::Post/11280&lt;span class=&quot;nt&quot;&gt;&amp;lt;/id&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;published&amp;gt;&lt;/span&gt;2021-05-14T19:48:10Z&lt;span class=&quot;nt&quot;&gt;&amp;lt;/published&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;updated&amp;gt;&lt;/span&gt;2021-05-23T15:15:38Z&lt;span class=&quot;nt&quot;&gt;&amp;lt;/updated&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Testing HEY world&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
...
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/entry&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;front_matter&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;date: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;published&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;localtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;last_modified_at: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;updated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;localtime&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;layout: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;post&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;tags: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;title: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;title&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;transform_keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The important part here is to make sure that all Hash keys are strings, otherwise, a YAML dump would generate Symbols which Jekyll doesn’t expect.&lt;/p&gt;

&lt;h2 id=&quot;file-generation&quot;&gt;File Generation&lt;/h2&gt;

&lt;p&gt;To keep this as simple as possible, I decided to reload all posts from the external feed every time I run the script, deleting every post that might have already been there. In case of &lt;a href=&quot;https://stex.codes&quot;&gt;stex.codes&lt;/a&gt;, this is done when building its docker container for deployment in CI.&lt;/p&gt;

&lt;p&gt;I tried using an own collection (= an own folder) in Jekyll for these posts, but those behave slightly different from normal posts and require a bit more configuration to be included in the main feed. Therefore, I decided to simply add a distinct pattern to their file names while still following Jekyll’s naming conventions:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://world.hey.com/stex/3b112301/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCR0dQSUJnPSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--70ce5ff444a619de3fa29d3428bcf5eccb1312ef/image.png?disposition=attachment&quot; title=&quot;Download image.png&quot;&gt;&lt;img src=&quot;https://world.hey.com/stex/3b112301/representations/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCR0dQSUJnPSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--70ce5ff444a619de3fa29d3428bcf5eccb1312ef/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDam9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2RkhKbGMybDZaVjkwYjE5c2FXMXBkRnNIYVFLQUIya0NBQVU2REhGMVlXeHBkSGxwU3pvTGJHOWhaR1Z5ZXdZNkNYQmhaMlV3T2cxamIyRnNaWE5qWlZRPSIsImV4cCI6bnVsbCwicHVyIjoidmFyaWF0aW9uIn19--946116ea0c454412635aa7309bd9472bf633014c/image.png&quot; alt=&quot;image.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This allows me to remove all possibly existing posts before loading the feed again:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;FileUtils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rm_rf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;POSTS_DIR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*--hey--*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;re-building-the-website-on-feed-changes&quot;&gt;Re-Building the Website on Feed Changes&lt;/h2&gt;

&lt;p&gt;Since changes to HEY World should be synced over to my blog, I wrote &lt;a href=&quot;https://github.com/Stex/url_watcher&quot;&gt;a small script / docker image&lt;/a&gt; to watch for changes and trigger a docker hub build. I didn’t find a better solution than polling yet, unfortunately.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Well, it works. I’ll have to adjust a few styles on the website to e.g. prohibit smaller images being displayed in full width, but creating a blog post through my email client is definitely a lot easier than having to code it. And since I’m still able to create more complex posts directly in Jekyll, I’ll go with this for all simpler topics for now.&lt;/p&gt;

</description>
        <pubDate>Mon, 24 May 2021 22:31:08 +0200</pubDate>
        
        <link>/2021/05/24/hey-importing-an-external-feed-into-jekyll.html</link>
          
        
            <category>hey</category>
        
            <category>jekyll</category>
        
            <category>ruby</category>
        
          
        
          
      </item>
    
    <item>
        <title>Testing HEY world</title>
        <description>&lt;p&gt;Test Post for writing short posts in HEY World and importing them into Jekyll (with syntax highlighting and tags). Works fine (up to a certain extend) without cluttering the output in case someone would really subscribe to this via email.&lt;/p&gt;

&lt;p&gt;I set up &lt;a href=&quot;https://stex.codes&quot;&gt;stex.codes&lt;/a&gt; a while back in an attempt to have an online CV, but also to start blogging about technical topics regularly again and chose Jekyll since Wordpress seems a bit too big and bloated for what I needed and I liked the idea of having static content.&lt;/p&gt;

&lt;p&gt;But when publishing a 2 paragraph long post becomes a project that takes an hour, I often don’t even want to start. Same thing as hanging your guitar on the wall ready to play rather than having to get it out of its case every time. It just doesn’t work. Therefore, I’ll give HEY World a shot. Say what you want about Basecamp in its current state of -1/3 employees, but they still manage to build bridges between “old” technology and the modern web.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://world.hey.com/stex/2bfcf2c0/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCT09qZHhjPSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--087c765c53e9fcbdc560dfc5728b0f9aa1787e0d/beaver_happy.png?disposition=attachment&quot; title=&quot;Download beaver\_happy.png&quot;&gt;&lt;img src=&quot;https://world.hey.com/stex/2bfcf2c0/representations/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBCT09qZHhjPSIsImV4cCI6bnVsbCwicHVyIjoiYmxvYl9pZCJ9fQ==--087c765c53e9fcbdc560dfc5728b0f9aa1787e0d/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaDdDam9MWm05eWJXRjBTU0lJY0c1bkJqb0dSVlE2RkhKbGMybDZaVjkwYjE5c2FXMXBkRnNIYVFLQUIya0NBQVU2REhGMVlXeHBkSGxwU3pvTGJHOWhaR1Z5ZXdZNkNYQmhaMlV3T2cxamIyRnNaWE5qWlZRPSIsImV4cCI6bnVsbCwicHVyIjoidmFyaWF0aW9uIn19--946116ea0c454412635aa7309bd9472bf633014c/beaver_happy.png&quot; alt=&quot;beaver_happy.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Beaver test image above)&lt;/p&gt;

&lt;p&gt;Not sure if it will be enough for my needs when it comes to e.g. code embeds, but it’s worth a try. Maybe I’ll find a good way to display a mix of Jekyll and HEY World posts on my blog through the RSS feed, that might be the perfect solution.&lt;/p&gt;

&lt;p&gt;Quick test of syntax highlighting (or probably the lack of it):&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;yaml&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Neph&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Acts as a registry of everything read from the local neph.yml file.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# All other classes should only act with this class instead of processing the file on their own.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Config&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Neph&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Refinements&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;exists?&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;exist?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;environments&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@environments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_yaml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;environments&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;no&quot;&gt;Environment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;symbolize_keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;tasks&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;tasks&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@tasks&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config_yaml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;tasks&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;no&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;task_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;symbolize_keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

      &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;config_path&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expand_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;neph.yml&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;config_yaml&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;Psych&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;safe_load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!-- HTML Comment --&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;em&amp;gt;&lt;/span&gt;HTML&lt;span class=&quot;nt&quot;&gt;&amp;lt;/em&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;strong&amp;gt;&lt;/span&gt;Test!&lt;span class=&quot;nt&quot;&gt;&amp;lt;/strong&amp;gt;&lt;/span&gt;
   &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;a b c&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Classes?&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Edit: OK, no syntax highlighting - but that’s ok. I’ll experiment a bit with it.&lt;br /&gt;
Edit 2: Got syntax highlighting working in Jekyll at least with a custom magic comment at the bottom of the code block 🙂&lt;br /&gt;
Edit 3: Just saw that all empty lines are removed from code blocks now, that should probably be changed for readability 🙈&lt;br /&gt;
Edit 4: The removal of empty lines was actually done by the HTML prettification I had in place during build. Removed it now as it did more harm than good.&lt;/p&gt;

&lt;p&gt;HEY World post is here btw: &lt;a href=&quot;https://world.hey.com/stex/testing-hey-world-2bfcf2c0&quot;&gt;https://world.hey.com/stex/testing-hey-world-2bfcf2c0&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Fri, 14 May 2021 21:48:10 +0200</pubDate>
        
        <link>/2021/05/14/hey-testing-hey-world.html</link>
          
        
            <category>hey</category>
        
            <category>jekyll</category>
        
          
        
          
      </item>
    
    <item>
        <title>Cypress on Rails (Talk)</title>
        <description>&lt;p&gt;A talk about how to replace Capybara with &lt;a href=&quot;https://cypress.io&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;cypress.io&lt;/a&gt; for E2E tests
while maintaining all the nice features like using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FactoryBot&lt;/code&gt; to generate test data on-the-fly. 
Held on the December meeting of the &lt;a href=&quot;https://hamburg.onruby.de/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Hamburg Ruby UserGroup&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As this is an interesting topic, I’ll probably write a proper blog post about it in the future.&lt;br /&gt;
Until then, I’ll provide my slides and the demo application I created for the talk here.
It contains both capybara and cypress examples and should give a good introduction on
how to start using cypress with Rails.&lt;/p&gt;

&lt;p&gt;&lt;i class=&quot;fas fa-external-link-alt fa-fw&quot;&gt;&lt;/i&gt; &lt;a href=&quot;https://github.com/stex/cypress_demo&quot;&gt;Demo Application&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;i class=&quot;fas fa-download fa-fw&quot;&gt;&lt;/i&gt; &lt;a href=&quot;/assets/files/cypress_on_rails_talk.pdf&quot;&gt;Slides&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Wed, 09 Dec 2020 00:00:00 +0100</pubDate>
        
        <link>/2020/12/09/cypress-on-rails-talk.html</link>
          
        
            <category>cypress</category>
        
            <category>rails</category>
        
            <category>end-to-end-tests</category>
        
            <category>capybara</category>
        
            <category>talk</category>
        
          
        
            <category>programming</category>
        
          
      </item>
    
    <item>
        <title>Adding Comments to a Jekyll Blog</title>
        <description>&lt;p&gt;I’m pretty happy with Jekyll and the static HTML pages it creates, but one thing every Wordpress blog features is clearly missing: a comment section.
Yes, it mostly collects either dust or bitcoin scams these days, but there’s still the chance someone actually has a question or remark about the thing I wrote.&lt;/p&gt;

&lt;p&gt;While I could have built a simple service myself, I’d then have to take care of e.g. spam filtering and generally maintaining it,
so I decided to use something existing. Of course Disqus came to mind, but if I’d include that into my page, I could as well add
GA and a facebook pixel for good measure.&lt;/p&gt;

&lt;p&gt;Surely I wasn’t the first one with this problem, so I searched for a bit. There were a lot of possible solutions (many of them no longer maintained),
 but two of them really caught my eye: &lt;a href=&quot;https://staticman.net/&quot; target=&quot;_blank&quot;&gt;Staticman&lt;/a&gt; and &lt;a href=&quot;https://utteranc.es/&quot; target=&quot;_blank&quot;&gt;utterances&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Both of them are open source and use Github as “database” for comments, but in very different ways. Let’s take a look:&lt;/p&gt;

&lt;h2 id=&quot;staticman&quot;&gt;Staticman&lt;/h2&gt;

&lt;p&gt;Staticman uses Github &lt;strong&gt;pull requests&lt;/strong&gt; to add new comments as actual files to the homepage repo. You just have to point your comment form to
the Staticman API, add the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;staticmanapp&lt;/code&gt; to your repo (so it can create the PRs) and you’re good to go.&lt;/p&gt;

&lt;p&gt;Every time a user submits the comment form, a new PR is created and - depending on your configuration - automatically merged or
marked for review. Each PR contains a simple &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;YAML&lt;/code&gt; file with the form data the user submitted which can easily be processed by Jekyll during compilation 
(see &lt;a href=&quot;https://github.com/eduardoboucas/popcorn&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt; for an example repo).&lt;/p&gt;

&lt;p&gt;Staticman can be self-hosted and comes with a lot of additional features like Akismet integration for spam checking or Mailgun for
email notifications about new comments, but it’s its main feature that made me not choose it: It automatically alters my repository.&lt;/p&gt;

&lt;p&gt;I like the idea of having my whole page as static files, including comments, but to be honest: As long as the comments are stored in
a database outside my page, I can still move it to a different server without losing anything. And I really don’t like the idea of
a service pushing code to my repository with whatever a user writes into a comments form (even if I review them before).&lt;/p&gt;

&lt;p&gt;This brings us to the second point I’m not really happy about: Staticman saves exactly what the user entered into the form
in the repo for me to render in my layout. While this allows for a lot of customization (the demo page uses it for movie reviews),
I still have to add the convenience for the user myself. Also, I’d have to make sure all user content is properly sanitized.&lt;/p&gt;

&lt;h3 id=&quot;short-version&quot;&gt;Short version:&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Users don’t need a Github account to comment&lt;/li&gt;
  &lt;li&gt;Integration with Akismet for spam filtering&lt;/li&gt;
  &lt;li&gt;Comments can contain custom fields like a star score (0-5)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Adds user generated content to my repo (I know, that’s the gimmick, but still…)&lt;/li&gt;
  &lt;li&gt;Rendering the comments in Jekyll has to be built, including proper sanitizing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;utterances&quot;&gt;utterances&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;utterances&lt;/em&gt; uses Github &lt;strong&gt;issues&lt;/strong&gt; to store user comments. 
It does so by sending XHR requests to its API (also open source) which communicates with the Github API behind the scenes.&lt;/p&gt;

&lt;p&gt;When the first user creates a comment on a post, a new issue is automatically created on Github. For each additional comment,
the same issue is re-used by adding a comment to its thread. Their &lt;a href=&quot;https://github.com/utterance/utterances/issues/1&quot; target=&quot;_blank&quot;&gt;index page issue&lt;/a&gt; is probably
the best example for how this works.&lt;/p&gt;

&lt;p&gt;Compared to &lt;em&gt;Staticman&lt;/em&gt;, the installation is pretty easy. You just have to insert a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag into your page with
some configuration options and you’re good to go.&lt;/p&gt;

&lt;p&gt;The script automatically fetches all existing comments and inserts them into the page in Github’s own style, making a user
feel pretty much at home. It also inserts a form to add more comments which pretty much behaves like its equivalent on Github, minus
the formatting toolbar. It does have full GFM support though.&lt;/p&gt;

&lt;p&gt;Using the Github API like this leads to two requirements for a user to comment:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. They need a Github account to comment (since they are basically commenting on a Github issue)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I honestly see this as a positive point. I’ll mostly write about tech stuff and most of the people who might end up here will have a Github account.
This should also act as a Spam filter to some degree as at least the drive by bots won’t be able to comment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. They have to allow the utterances Github app to “act on their behalf” to post the comment.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Allowing a Github application to access your account is always a tricky decision. Since their API is also open source, I could host it myself, but
I think that’s even worse. While I’d know for sure that it’s harmless, people would have to give access to a “stex.codes” application… I think it’s easier to 
go with the 3k stars one on Github than with my own installation.&lt;/p&gt;

&lt;p&gt;Also, Github makes it pretty clear that a comment wasn’t made by the user directly:&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;&lt;a href=&quot;/assets/images/posts/comments-bot.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/comments-bot.png&quot; alt=&quot;Bot-posted comment example&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Alternatively, the user can of course add the comment directly on Github, making having an account there the only requirement.&lt;/p&gt;

&lt;h3 id=&quot;short-version-1&quot;&gt;Short version:&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Pros&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Easy setup through a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag&lt;/li&gt;
  &lt;li&gt;It feels like writing a Github comment and looks like a Github comment (and is a Github comment).&lt;/li&gt;
  &lt;li&gt;It requires a Github account to comment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It requires a Github account to comment.&lt;/li&gt;
  &lt;li&gt;The user has to give the utteranc.es Github app the permission to “act on their behalf”&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;As you can see on this page, I went with &lt;em&gt;utterances&lt;/em&gt;.&lt;br /&gt;
Since both the library and Github application are open source, I’m fine with using it myself. 
It might lead to fewer people commenting (if someone makes it here anyway that is), but I like the issue flow
a lot more than &lt;em&gt;Staticman&lt;/em&gt;’s PR approach. Both are very interesting from a technical standpoint though.&lt;/p&gt;

&lt;p&gt;Regarding placement and styling, I went with the default Github dark mode for now, but will change that to another
white container below the post. It will be easier to read.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;strong&gt;Update (06.09.2020/18.01.2020)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;utterances&lt;/em&gt; by default places the content of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;title&amp;gt;&lt;/code&gt; attribute inside its issue names and uses it to find the matching issue for a post.&lt;br /&gt;
I changed this post’s title and sure enough the comments were gone.&lt;/p&gt;

&lt;p&gt;To work around this, I decided to use an own term to put into the issue per page and use its URL as fallback. This way, I have a little more freedom
to change posts after publishing them.&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{% unless page.hide_comments %}
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://utteranc.es/client.js&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;repo=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stex/stex.codes&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;issue-term=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{% if page.comment_issue_term %}{{ page.comment_issue_term }}{% else %}url{% endif %}&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;label=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;comment&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;theme=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;github-dark&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;crossorigin=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;anonymous&quot;&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;async&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
{% endunless %}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This allows setting the issue term in the posts &lt;a href=&quot;https://jekyllrb.com/docs/front-matter/&quot;&gt;front matter&lt;/a&gt; as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;comment_issue_term: Something&lt;/code&gt; or hide comments completely by providing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hide_comments: true&lt;/code&gt;.&lt;/p&gt;
</description>
        <pubDate>Thu, 03 Sep 2020 18:00:00 +0200</pubDate>
        
        <link>/2020/09/03/adding-comments-to-a-jekyll-blog.html</link>
          
        
            <category>jekyll</category>
        
          
        
            <category>programming</category>
        
          
      </item>
    
    <item>
        <title>Building an Alfred Workflow to export Attachments from Evernote</title>
        <description>&lt;p&gt;This post is about building an Alfred workflow that allows exporting all image attachments of the currently opened Evernote note as PDF.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;update-2021-02-03&quot;&gt;Update (2021-02-03)&lt;/h3&gt;

&lt;p&gt;Judging by a &lt;a href=&quot;https://twitter.com/evernotehelps/status/1354859907212783619&quot; target=&quot;_blank&quot;&gt;Tweet from the Evernote Support&lt;/a&gt;, it looks like they are planning to get applescript support back in the future.&lt;/p&gt;

&lt;p&gt;Really hoping they do, currently, there doesn’t seem to be an easy, non-API solution to automate anything.&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;update-2021-01-18&quot;&gt;Update (2021-01-18)&lt;/h3&gt;

&lt;p&gt;I updated the workflow for the new Evernote electron app.&lt;/p&gt;

&lt;p&gt;Since Evernote supports neither Applescript nor &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x-callback-url&lt;/code&gt; now, I had to work around it Selenium style and click on each UI element from Applescript.
It works, but doesn’t look too elegant.&lt;/p&gt;

&lt;p&gt;The new workflow can be found here: &lt;a href=&quot;https://github.com/Stex/alfred-evernote-helpers/tree/master/evernote-attachments-pdf&quot; target=&quot;_blank&quot;&gt;Source Code on Github&lt;/a&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h3 id=&quot;update-2020-10-09&quot;&gt;Update (2020-10-09)&lt;/h3&gt;

&lt;p&gt;With the latest evernote update to electron, it looks like applescript support was dropped completely, therefore, this workflow
isn’t working any more.&lt;/p&gt;

&lt;p&gt;Since I still need a way to export attachments, I’ll look into using the Evernote API some time, but that won’t be as accessible
to other users since you  need an API key - or trust a random dude’s application to connect to your Evernote account.&lt;/p&gt;

&lt;p&gt;I’ll update this post again in case I find another solution.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I recently started using Evernote for document management purposes. I’m not the biggest fan of its note taking
capabilities, but the convenience of taking a picture with the mobile app and having it optimized and indexed
as a document is pretty amazing.&lt;/p&gt;

&lt;p&gt;However, I still wanted to be able to export the documents I scanned as PDFs which proofed a bit more difficult than expected:
Evernote saves its scanned documents as one PNG image per page and attaches each one to the note.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, why not just print to PDF?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My first idea was indeed to use the print dialog and generate a PDF out of it. However, Evernote adds some pretty substancial margin around
the actual image, probably because of lower dpi:&lt;/p&gt;

&lt;div class=&quot;flex flex-row&quot;&gt;
    &lt;div class=&quot;item&quot;&gt;
        &lt;div class=&quot;text-center&quot;&gt;Actual Image&lt;/div&gt;
        &lt;img src=&quot;/assets/images/posts/evernote-actual-image.png&quot; alt=&quot;Scanned Evernote Attachment&quot; /&gt;
    &lt;/div&gt;

    &lt;div class=&quot;item&quot;&gt;
        &lt;div class=&quot;text-center&quot;&gt;Print to PDF output&lt;/div&gt;
        &lt;img src=&quot;/assets/images/posts/evernote-print-to-pdf.png&quot; alt=&quot;Print to PDF output&quot; /&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;As you can see, I would get a tiny image inside an A4 PDF, not exactly what I was looking for.&lt;/p&gt;

&lt;p&gt;Since I didn’t find a proper solution for this problem on the web, I decided to build one myself.&lt;/p&gt;

&lt;h2 id=&quot;the-applescript-part&quot;&gt;The Applescript Part&lt;/h2&gt;

&lt;p&gt;Luckily, Evernote has quite extensive Applescript support by now. It doesn’t necessarily make it easy to
achieve exactly what you’re trying to do, but it at least gives you a lot of information.&lt;/p&gt;

&lt;p&gt;&lt;i class=&quot;far fa-lightbulb fa-fw&quot;&gt;&lt;/i&gt;If you are like me and only visit Applescript when you absolutely have to,
here’s something I learned: Most applications with Applescript support come with a dictionary of the things they support.
To view it, open the Script Editor, choose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File&lt;/code&gt; -&amp;gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Open Dictionary&lt;/code&gt; and select the application you’d like to explore.&lt;/p&gt;

&lt;p&gt;I’ll go through the steps I took to get to my final solution and try to show off a few problems I encountered and had to work around.&lt;/p&gt;

&lt;h3 id=&quot;getting-the-current-notes-data&quot;&gt;Getting the Current Note’s Data&lt;/h3&gt;

&lt;p&gt;Assuming that the user didn’t select a bunch of notes at once and just opened one by clicking on it,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;selection&lt;/code&gt; is a 1 element list that contains exactly this note object.&lt;/p&gt;

&lt;div class=&quot;language-applescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Evernote&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;notesList&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;selection&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oNote&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;notesList&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oNote&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;extracting-the-attachments&quot;&gt;Extracting the Attachments&lt;/h3&gt;

&lt;p&gt;I searched the Evernote Applescript dictionary and found that each note has a list of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Attachment&lt;/code&gt;s
with each of them responding to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write&lt;/code&gt; method to extract them to the hard disk. Couldn’t be so difficult then, right?&lt;/p&gt;

&lt;p&gt;First, I had to find a suitable filename for the images when saving them to disk.
And I needed them in a certain order to pass them into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;convert&lt;/code&gt; to create a PDF out of them.&lt;/p&gt;

&lt;p&gt;The Evernote dictionary gave me a few options here:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;“filename (text or missing value, r/o) : The attachment’s original filename, if available.”&lt;/li&gt;
  &lt;li&gt;“hash (text, r/o) : The attachment’s hash (used to identify the attachment in the note’s ENML).”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Since filename was not a guaranteed value neither it nor hash had anything to do with the order of the attachments
inside the note, I went with building an own filename using a for-loop’s index variable:&lt;/p&gt;

&lt;div class=&quot;language-applescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;attachments&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oAttachment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;attachments&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oAttachment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/Users/stex/Downloads/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.png&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Looks like it should work, but doesn’t. Instead, I was presented with my first error:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;error “Evernote got an error: “31EB6536-288F-4A4D-8ADA-1D455165115E.png” couldn’t be copied because you don’t have permission to access “Downloads”.” number 513&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What happened here?
With the more recent versions of macOS, Apple followed what they already had in place for iOS applications: Each app runs inside its own little
file system sandbox and you have to explicitly give it access to folders outside of it. Since I didn’t find a way to give Evernote access to
a certain folder from inside Applescript, I chose an output folder instead that I knew Evernote had write access to - its own sandbox.&lt;/p&gt;

&lt;div class=&quot;language-applescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;evernoteDataFolder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;system attribute&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;HOME&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/Library/Containers/com.evernote.Evernote/Data/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;attachments&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oAttachment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;attachments&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oAttachment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;evernoteDataFolder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.png&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That got rid of the permission error, but reveiled something else.
I was absolutely convinced that the list of attachments Evernote gave me inside Applescript would follow the
order of attachments inside the note. But no, it follows the random filenames Evernote assigned them leaving me with
no guaranteed order at all.&lt;/p&gt;

&lt;p&gt;As far as I could see, there was no way to get the actual attachment order from Evernote, so how to proceed?&lt;/p&gt;

&lt;h3 id=&quot;using-the-note-content-to-get-the-attachment-order&quot;&gt;Using the Note Content to get the Attachment Order&lt;/h3&gt;

&lt;p&gt;Luckily, Evernote gives us access to the note’s content both in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HTML&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ENML&lt;/code&gt; format.
While the former is not of interest here, the latter is basically an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;XML&lt;/code&gt; file Evernote uses internally.&lt;/p&gt;

&lt;p&gt;Let’s take a look at such a file:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE en-note SYSTEM &quot;http://xml.evernote.com/pub/enml2.dtd&quot;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;en-note&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;en-media&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;hash=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;270493a2b1a89ceeb2528f1c0e97d1f5&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;title=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Attachment&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1979&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;image/png&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;en-media&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;hash=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0cb8d04258fdbfe33739b2529d81fdb5&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;title=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Attachment&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1440&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;image/png&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;br/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/en-note&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, it contains an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;en-media&lt;/code&gt; tag for each attachment in the note with, including a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash&lt;/code&gt; attribute
which corresponds to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash&lt;/code&gt; property available for each &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;note&lt;/code&gt; object inside Applescript.&lt;/p&gt;

&lt;p&gt;At this point I decided that Applescript wasn’t enough to solve my problem completely,
but I still had to use it to extract all the necessary information from Evernote and make it available to another script.
Namely, I needed the following data outside of Applescript:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;The note’s ENML content&lt;/li&gt;
  &lt;li&gt;The attachment files saved with their hash as filenames&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both could easily be achieved:&lt;/p&gt;

&lt;div class=&quot;language-applescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oNote&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;noteContent&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ENML&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;do shell script&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;echo '&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;noteContent&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;' &amp;gt; '&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;evernoteDataFolder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;note.xml'&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oAttachment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;attachments&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;noteHash&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oAttachment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oAttachment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;evernoteDataFolder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;noteHash&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.png&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Luckily, Applescript gives us access to shell scripting with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;do shell script&lt;/code&gt;. This makes saving a string to a file by redirecting an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;echo&lt;/code&gt;
output easy enough - from what I found on the internet, this seems to be the solution used by most developers.&lt;/p&gt;

&lt;p&gt;After cleaning up a bit and putting the exported files into a subfolder to not pollute Evernote’s sandbox too much, I ended up with
the following code. Please note that I return &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notePath&lt;/code&gt; as script result which points to the folder I saved all the files in.
We’ll need this path in the next step.&lt;/p&gt;

&lt;div class=&quot;language-applescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# A helper function to create the temp directory to place our files in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;createNoteDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;do shell script&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rm -rf '&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;'&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;do shell script&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;mkdir -p '&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;'&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;createNoteDir&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Evernote&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;notesList&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;selection&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oNote&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;notesList&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;evernoteDataFolder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;system attribute&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;HOME&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/Library/Containers/com.evernote.Evernote/Data&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oNote&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;noteTitle&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;noteContent&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ENML&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# We have to use a temp path that Evernote has access to... and nothing outside&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# its sandboxed container is guaranteed to be.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;notePath&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;evernoteDataFolder&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/attachment_export/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;noteTitle&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;my&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;createNoteDir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;notePath&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Save the note's XML content in a file we can later access.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# We need it to find out the correct attachment order as Evernote&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# by default orders them by filename&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;do shell script&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;echo '&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;noteContent&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;' &amp;gt; '&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;notePath&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;note.xml'&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oAttachment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;attachments&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# Save each attachment using its hash as filename.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;# This way, we can match it to the values from the XML content later.&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;noteHash&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oAttachment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;imgPath&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;notePath&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;noteHash&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.png&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

      &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;oAttachment&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;imgPath&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;repeat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;notePath&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running the this script with a note titled “Notiz” containing 2 attachments leads us to the following content on our hard drive:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;i class=&quot;far fa-folder-open fa-fw&quot;&gt;&lt;/i&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/Users/stex/Library/Containers/com.evernote.Evernote/Data/attachment_export/Notiz&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;i class=&quot;far fa-image fa-fw&quot;&gt;&lt;/i&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0cb8d04258fdbfe33739b2529d81fdb5.png&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;i class=&quot;far fa-image fa-fw&quot;&gt;&lt;/i&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;270493a2b1a89ceeb2528f1c0e97d1f5.png&lt;/code&gt;&lt;/li&gt;
      &lt;li&gt;&lt;i class=&quot;far fa-file-alt fa-fw&quot;&gt;&lt;/i&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;note.xml&lt;/code&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;the-ruby-part&quot;&gt;The Ruby Part&lt;/h2&gt;

&lt;p&gt;Now that all the necessary information was available outside of Evernote, I needed to feed it to another script
which would find out the actual attachment order and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;convert&lt;/code&gt; for me.
I chose Ruby as Alfred supports it well and… I just like Ruby.&lt;/p&gt;

&lt;p&gt;The script assumes that the path the note information was saved to is passed in as first command line argument.&lt;/p&gt;

&lt;p&gt;First of all, I had to get the note’s XML content:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;fileutils&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;pathname&quot;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;NOTE_PATH&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;NOTE_XML_FILE&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NOTE_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;note.xml&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;NOTE_XML_FILE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As a reminder, this gives us a file containing multiple tags with the attachment information:&lt;/p&gt;

&lt;div class=&quot;language-xml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;en-media&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;hash=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;270493a2b1a89ceeb2528f1c0e97d1f5&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;title=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Attachment&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;1979&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;image/png&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since I planned to put this into an Alfred workflow by now, I decided not to use a library like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nokogiri&lt;/code&gt;
to parse the XML since it would require other users to have it globally installed as a gem.&lt;/p&gt;

&lt;p&gt;Instead, I went with a simple regular expression and capture groups to get the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hash&lt;/code&gt; values out of each tag:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;attachments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/en-media hash=&quot;(\w+)&quot;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;'&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NOTE_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;'&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For the note exported above, this would leave us with the full pathnames to each attachment in the correct order:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;attachments&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [&quot;/Users/stex/Library/.../270493a2b1a89ceeb2528f1c0e97d1f5.png&quot;, &quot;/Users/stex/Library/.../0cb8d04258fdbfe33739b2529d81fdb5.png&quot;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All that’s left to do now is to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;convert&lt;/code&gt; with the attachments as input files and create a PDF:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;PDF_OUTPUT_FILE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/Users/stex/Downloads&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;NOTE_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.pdf&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;convert &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attachments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; '&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PDF_OUTPUT_FILE&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;'&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The final script looks as follows. I added a few environment variables to make it customisable for other
users and cleaned up Evernote’s sandbox:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;fileutils&quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;pathname&quot;&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;NOTE_PATH&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Pathname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;NOTE_XML_FILE&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NOTE_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;note.xml&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;PDF_OUTPUT_FILE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;PDF_OUTPUT_FOLDER&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;NOTE_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;basename&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.pdf&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;NOTE_XML_FILE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;attachments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/en-media hash=&quot;(\w+)&quot;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;'&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NOTE_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.png&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;'&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;system&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;CONVERT_PATH&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attachments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot; &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; '&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PDF_OUTPUT_FILE&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;'&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;FileUtils&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rm_rf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;NOTE_PATH&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PDF_OUTPUT_FILE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Please note that I decided to pass in the full path to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;convert&lt;/code&gt; utility here as an environment variable.
Alfred runs its code in an environment without sourcing your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.bash_profile&lt;/code&gt; or similar, leading to a different &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PATH&lt;/code&gt; than you’d expect.&lt;/p&gt;

&lt;p&gt;By default, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;convert&lt;/code&gt; resides in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/bin&lt;/code&gt; (when installed through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;brew&lt;/code&gt;), but I wanted to make sure other users
could modify the path if necessary.&lt;/p&gt;

&lt;h2 id=&quot;the-alfred-part&quot;&gt;The Alfred Part&lt;/h2&gt;

&lt;p&gt;Now with both scripts working on their own, I started building a new Alfred workflow to call them in succession.
Creating the workflow was pretty straight forward:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Add a trigger&lt;/li&gt;
  &lt;li&gt;Call each script and pipe its output into the next script as command line argument&lt;/li&gt;
  &lt;li&gt;Add some convenience for the user (optional)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;1-adding-a-trigger&quot;&gt;1. Adding a Trigger&lt;/h3&gt;

&lt;p&gt;While Alfred supports a lot of different trigger events (e.g. hotkeys or Applescript), I went with a simple keyword here.
Whenever the user types &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;evernote-attachments-pdf&lt;/code&gt; in Alfred (auto completion is available), it would offer the corresponding command.&lt;/p&gt;

&lt;div class=&quot;flex flex-row&quot;&gt;
  &lt;div class=&quot;item text-center&quot;&gt;&lt;a href=&quot;/assets/images/posts/evernote-alfred-trigger.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/evernote-alfred-trigger.png&quot; alt=&quot;Alfred Workflow Trigger Dialog&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
  &lt;div class=&quot;item text-center&quot;&gt;&lt;a href=&quot;/assets/images/posts/evernote-alfred-command.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/evernote-alfred-command.png&quot; alt=&quot;Alfred Input&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;h3 id=&quot;2-running-both-scripts-in-succession&quot;&gt;2. Running both Scripts in Succession&lt;/h3&gt;

&lt;p&gt;I went with two “Run Script” actions for the Applescript and Ruby parts.
For the Applescript, the input setting didn’t matter, but I had to make sure to set the Ruby script to
take its input as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ARGV&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As mentioned before, Alfred always “pipes” the console output of a script to the next action in its workflow.
For Applescript, the value after &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return&lt;/code&gt; is automatically printed out, in our Ruby script, we had to do it manually through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;puts&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;flex flex-row&quot;&gt;
  &lt;div class=&quot;item text-center&quot;&gt;&lt;a href=&quot;/assets/images/posts/evernote-alfred-scripts.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/evernote-alfred-scripts.png&quot; alt=&quot;Alfred Workflow Scripts&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
  &lt;div class=&quot;item text-center&quot;&gt;&lt;a href=&quot;/assets/images/posts/evernote-alfred-script-settings.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/evernote-alfred-script-settings.png&quot; alt=&quot;Alfred Workflow Script Settings&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The Ruby script could be used as is, for the Applescript, I had to wrap my code inside a sub-routine:&lt;/p&gt;

&lt;div class=&quot;language-applescript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
 &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With this done, we can already run our workflow from Alfred and are presented with a neat PDF inside the output directory.
I decided to go a bit further though and give some sort of response to the user to let them know everything worked as expected.&lt;/p&gt;

&lt;h3 id=&quot;3-adding-some-convenience&quot;&gt;3. Adding some Convenience&lt;/h3&gt;

&lt;p&gt;Many applications open the directory they put a file in after its creation so I went with the flow and added a “Reveil File in Finder” action to the workflow.
Since our Ruby script’s output is the full path to the output directory, I just had to connect it to the Ruby script and everything worked as expected:&lt;/p&gt;

&lt;div class=&quot;text-center&quot;&gt;&lt;a href=&quot;/assets/images/posts/evernote-reveil-in-finder.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/evernote-reveil-in-finder.png&quot; alt=&quot;Alfred Reveil in Finder Block&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Since I personally find this behaviour a bit annoying from time to time, I decided to give the user a choice here.
I defined another environment variable named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;REVEIL_IN_FINDER&lt;/code&gt; and added a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;conditional&lt;/code&gt; block to the workflow:&lt;/p&gt;

&lt;div class=&quot;flex flex-row&quot;&gt;
  &lt;div class=&quot;item text-center&quot;&gt;&lt;a href=&quot;/assets/images/posts/evernote-alfred-conditional.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/evernote-alfred-conditional.png&quot; alt=&quot;Alfred Workflow Conditional&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
  &lt;div class=&quot;item text-center&quot;&gt;&lt;a href=&quot;/assets/images/posts/evernote-alfred-conditional-settings.png&quot;&gt;&lt;img src=&quot;/assets/images/posts/evernote-alfred-conditional-settings.png&quot; alt=&quot;Alfred Workflow Conditional Settings&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;This way, the output folder from my Ruby script would either be sent to the “Reveil File in Finder” action or a notification would be shown instead.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;When I started with the Evernote Applescript Dictionary, I was convinced I would have this solved within half an hour… should have learned that after that many years of programming.&lt;/p&gt;

&lt;p&gt;While the app sandboxing took me the longest to figure out, it was the easiest to be solved in the end.
I was a bit disappointed by the Evernote documentation regarding its Applescript usage, e.g. the order attachments would be returned. This caused me to try a lot of different solutions to work
around each newfound behaviour until I finally settled with an additional script.&lt;/p&gt;

&lt;p&gt;Anyway, I learned a bit more about MacOS applications and scripting and got a nice PDF export out of it, so definitely worth it.&lt;/p&gt;
</description>
        <pubDate>Wed, 02 Sep 2020 19:00:00 +0200</pubDate>
        
        <link>/2020/09/02/evernote-attachment-workflow.html</link>
          
        
            <category>alfred</category>
        
            <category>evernote</category>
        
            <category>ruby</category>
        
            <category>applescript</category>
        
          
        
            <category>programming</category>
        
          
      </item>
    
  </channel>
</rss>
